当前位置: 首页 > news >正文

【Spring Boot】掌握 Spring 事务:隔离级别与传播机制解读与应用

前言

???本期讲解关于spring 事务传播机制介绍~~~

??感兴趣的小伙伴看一看小编主页:-CSDN博客

?? 你的点赞就是小编不断更新的最大动力

??那么废话不多说直接开整吧~~

目录

???1.事务的隔离级别

??1.1MySQL事务隔离级别

??1.2Spring事务隔离级别

???2.Spring事务传播机制

??2.1什么是事务的传播机制

??2.2事务隔离与传播的区别

??2.3事务的传播机制

??2.4事务传播机制代码演示

2.4.1REQUIRED

?2.4.2REQUIRES_NEW

2.4.3NEVER

2.4.4NESTED

??2.5NESTED和REQUIRED 区别

???3.总结

**??**1.事务的隔离级别

??1.1MySQL事务隔离级别

读未提交(READ UNCOMMITTED): 读未提交, 也叫未提交读. 该隔离级别的事务可以看到其他事务中未提交的数据.

因为其他事务未提交的数据可能会发回滚, 但是该隔离级别却可以读到, 我们把该级别读到的数据称之为脏数据, 这个问题称之为脏读.(就是一个事务还没有写完,另一个事务就在读了)

读提交(READ COMMITTED): 读已提交, 也叫提交读. 该隔离级别的事务能读取到已经提交事务的数据

该隔离级别不会有脏读的问题.但由于在事务的执中可以读取到其他事务提交的结果, 所以在不同时间的相同 SQL 查询可能会得到不同的结果, 这种现象叫做不可重复读

(大致就是,事务A在写完后,B读了之后,A又再次修改了,那么B再次读之后,就会发现两次的结果不一样)

可重复读(REPEATABLE READ): 事务不会读到其他事务对已有数据的修改, 即使其他事务已提交. 也就可以确保同事务多次查询的结果致, 但是其他事务新插的数据, 是可以感知到的. 这也就引发了幻读问题. 可重复读, 是 MySQL 的默认事务隔离级别.

如此级别的事务正在执时, 另个事务成功的插了某条数据, 但因为它每次查询的结果都是样的, 所以会导致查询不到这条数据, 重复插时失败(因为唯约束的原因). 明明在事务中查询不到这条信息,但就是插不进去, 这个现象叫幻读

串化(SERIALIZABLE): 序列化, 事务最隔离级别. 它会强制事务排序, 使之不会发冲突, 从解决了脏读, 不可重复读和幻读问题, 但因为执效率低, 所以真正使的场景并不多

??1.2Spring事务隔离级别

Spring 中事务隔离级别有5 种:

1. Isolation.DEFAULT : 以连接的数据库的事务隔离级别为主.
2. Isolation.READ_UNCOMMITTED : 读未提交, 对应SQL标准中 READ UNCOMMITTED
3. Isolation.READ_COMMITTED : 读已提交,对应SQL标准中 READ COMMITTED
4. Isolation.REPEATABLE_READ : 可重复读, 对应SQL标准中 REPEATABLE READ
5. Isolation.SERIALIZABLE : 串化, 对应SQL标准中 SERIALIZABLE

设置事务的隔离级别代码如下:

 @Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT)
    //设置所有回滚异常类型
    @RequestMapping("/r7")
    public Boolean r7(String userName, String password) throws IOException {
        Integer result = userService.registUser(userName, password);
        System.out.println("插入用户表, result: "+ result);
        if (true){
            throw new IOException();
        }

        return true;
    }

解释:

在代码中,注解里的参数rollbackfor指定所有异常都需要进行回滚,然后isolation指定是与数据库的事务隔离级别是一致的,那么这里的spring事务的隔离级别就是可重复读;

**??**2.Spring事务传播机制

??2.1什么是事务的传播机制

事务传播机制就是: 多个事务法存在调关系时, 事务是如何在这些法间进传播的

就比如,两个方法,都被transaction修饰了,假如这里的两个方法存在调用的关系,那么这里的事务是如何进行传播的,是使用A的事务,还是使用B的事务呢?

??2.2事务隔离与传播的区别

事务隔离级别解决的是多个事务同时调个数据库的问题

如下图:

事务传播机制解决的是个事务在多个节点(法)中传递的问题

??2.3事务的传播机制

@Transactional 注解持事务传播机制的设置, 通过 propagation 属性来指定传播为.
Spring 事务传播机制有以下 7 种:

B是被调用的一方(service),A是调用的一方(controller)

1. Propagation.REQUIRED : 默认的事务传播级别. 如果当前存在事务, 则加该事务. 如果当前没
有事务, 则创建个新的事务.)

A有事务,B就直接使用A的事务,如果A没有事务,B创建一个事务

2. Propagation.SUPPORTS : 如果当前存在事务, 则加该事务. 如果当前没有事务, 则以事务的式继续运.

A有事务,B就直接使用A的事务,如果A没有事务,B以非事务的方式进行运行

**3. Propagation.MANDATORY 😗*强制性. 如果当前存在事务, 则加该事务. 如果当前没有事务, 则
抛出异常.

A有事务,B就直接使用A的事务,如果A没有事务,那么就直接抛出异常

4. Propagation.REQUIRES_NEW : 创建个新的事务. 如果当前存在事务, 则把当前事务挂起. 也
就是说不管外部法是否开启事务, Propagation.REQUIRES_NEW 修饰的内部法都会新开
启的事务, 且开启的事务相互独, 互不扰.

就是不管A有无事务,B都创建新的事务

5. Propagation.NOT_SUPPORTED : 以事务式运, 如果当前存在事务, 则把当前事务挂起(不).

就是不管A有无事务,B都直接以非事务的方式进行运行

6. Propagation.NEVER : 以事务式运, 如果当前存在事务, 则抛出异常

如果A事务存在,那么就直接抛出异常

7. Propagation.NESTED : 如果当前存在事务, 则创建个事务作为当前事务的嵌套事务来运.
如果当前没有事务, 则该取值等价于 PROPAGATION_REQUIRED

没有事务就创建事务,有的话就干点其他的事情

??2.4事务传播机制代码演示
2.4.1REQUIRED

controller控制层,代表的A

@RequestMapping("/user")
@RestController
public class UserController2 {
    @Autowired
    private UserService userService;
    @Autowired
    private LogService logService;

    @Transactional(propagation = Propagation.REQUIRED)
    @RequestMapping("/p1")
    public String r3(String name, String password) {
        //??注册
        userService.registUser(name, password);
        //记录操作?志
        logService.insertLog(name, "??注册");
        return "p1";
    }
}

其余两个service:

登录日志打印:

@Service
public class LogService {
    @Autowired
    private LogInfoMapper logInfoMapper;
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertLog(String userName,String op){

        logInfoMapper.insert(userName,"用户注册");
        int a=10/0;
    }
}

user登录:

@Service
public class UserService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer registUser(String userName, String password) {

        Integer result = userInfoMapper.insert(userName, password);

        return result;

    }
}

输出情况,打印的日志如下:

1. p1 法开始事务
2. 注册, 插条数据 (执成功) (和p1 使同个事务)
3. 记录操作志, 插条数据(出现异常, 执失败) (和p1 使同个事务)
4. 因为步骤3出现异常, 事务回滚. 步骤2和3使同个事务, 所以步骤2的数据也回滚了.

2.4.2REQUIRES_NEW

我们将这里的两个service层改成REQUIRES_NEW

这里的其中一个事务进行了提交;

另一个代码存在算数异常的就没有进行提交

这里就是单独创建了自己的事务,这里的两个service层创建的两个事务就不会相互影响,所以其中一个提交,另一个进行了回滚的操作;

2.4.3NEVER

我们将其中一个代码传播机制改变

@Service
public class UserService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Transactional(propagation = Propagation.NEVER)
    public Integer registUser(String userName, String password) {

        Integer result = userInfoMapper.insert(userName, password);

        return result;

    }
}

输出的日志如下所示:

那么这里可以看到报错信息就是A调用层存在事务,导致报错;

2.4.4NESTED

将上述UserService 和LogService 中相关法事务传播机制改为 Propagation.NESTED

小编这里就不演示代码了,大家可以自己去试一试;

打印日志如下:

由于是嵌套事务, LogService 出现异常之后, 往上找调它的法和事务, 所以注册也失败
了.最终结果是两个数据都没有添加
p1事务可以认为是事务, 嵌套事务是事务. 事务出现异常, 事务也会回滚, 事务出现异常, 如果不进处理, 也会导致事务回滚(可以认为是REQUIRED,但是不完全是

??2.5NESTED和REQUIRED 区别

我们知道,当两个方法不存在问题时,这里的两种传播机制是没有啥区别的,但是当出现问题时,我们可以发现情况如上图所示,但是真的没有区别吗?答案是否定的;

@Service
public class LogService {
    @Autowired
    private LogInfoMapper logInfoMapper;
    @Transactional(propagation = Propagation.NESTED)
    public void insertLog(String userName,String op){
        try {
            int a=10/0;
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        logInfoMapper.insert(userName,"用户注册");   
    }
}

重新运程序, 发现表数据添加成功, 志表添加失败.


LogService 中的事务已经回滚, 但是嵌套事务不会回滚嵌套之前的事务, 也就是说嵌套事务可以实
现部分事务回滚

但是对于REQUIRED 如果回滚就是回滚所有事务, 不能实现部分事务的回滚. (因为属于同个事务)

嵌套事务之所以能够实现部分事务的回滚, 是因为事务中有个保存点(savepoint)的概念, 嵌套事务进之后相当于新建了个保存点, 滚回时只回滚到当前保存点.

这里是小编的理解,大家有问题或者质疑可以私信我哟~~~

**??**3.总结

**???**本期讲解了关于MySQL事务的隔离级别回顾,以及spring的事务隔离级别以及事务传播机制,分别从概念和代码进行了演示~~~

???~~~~最后希望与诸君共勉,共同进步!!!


???以上就是本期内容了, 感兴趣的话,就关注小编吧。

???期待你的关注~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/42476.html

相关文章:

  • OptiTrack光学跟踪系统:引领工厂机器人应用的革新浪潮
  • 【统计的思想】基于马尔科夫链的测试
  • SQL Server查询计划操作符(7.3)——查询计划相关操作符(7)
  • Android APK组成编译打包流程详解
  • Muduo + OpenSSL 网络交互完整流程
  • ubuntu系统安装playhouse三方库
  • 高性能PHP框架webman爬虫引擎插件,如何爬取数据
  • 2025-02-28 学习记录--C/C++-C语言 scanf 中,%s 不需要加
  • 面试(进阶) —虚拟列表在什么场景使用,如何实现?
  • Pytorch中的主要函数
  • 导游从业资格证有什么备考秘籍?
  • 【计网】物理层
  • 【LeetCode347】前k个高频元素
  • 北京大学DeepSeek系列-提示词工程和落地场景
  • 极简Redis速成学习
  • 【Mysql】:如何恢复误删的数据?
  • Spring Boot 启动与 Service 注入的 JVM 运行细节
  • MySQL慢查询分析与处理
  • Basler acA1920-40gc
  • RabbitMQ 学习路线与知识总结
  • Opencv 阈值与平滑处理
  • 京东外卖举办首批全职骑手代表签约仪式
  • az devops login报错:Failed to authenticate using the supplied token.
  • 广义表(C语言代码链式存储结构)
  • Linux基础33-C语言篇之字符串的基础操作【入门级】
  • 浅入浅出Selenium DevTools
  • 【数据结构】_顺序表
  • SringAop
  • 互联网医院实时数据监测智能分析系统设计概述(上)
  • 基于springboot后台管理的校园网站系统(源码+lw+部署文档+讲解),源码可白嫖!