【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 区别](#??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的事务隔离级别以及事务传播机制,分别从概念和代码进行了演示~~~

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


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

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

相关推荐
caihuayuan51 小时前
Vue生命周期&脚手架工程&Element-UI
java·大数据·spring boot·后端·课程设计
MaCa .BaKa2 小时前
37-智慧医疗服务平台(在线接诊/问诊)
java·vue.js·spring boot·tomcat·vue·maven
八股文领域大手子3 小时前
Spring Boot Controller 如何处理HTTP请求体
java·开发语言·sql·spring·spring cloud
tanxiaomi3 小时前
Java中对象集合转换的优雅实现【实体属性范围缩小为vo】:ListUtil.convert方法详解
java·spring boot·mybatis
小刘|3 小时前
Spring,SpringMVC,SpringBoot,SpringCloud的区别
spring boot·spring·spring cloud
明月与玄武4 小时前
Spring Boot中的拦截器!
java·spring boot·后端
为美好的生活献上中指4 小时前
java每日精进 5.07【框架之数据权限】
java·开发语言·mysql·spring·spring cloud·数据权限
菲兹园长4 小时前
SpringBoot统一功能处理
java·spring boot·后端
一刀到底2114 小时前
spring ai alibaba 使用 SystemPromptTemplate 很方便的集成 系统提示词
spring·ai alibaba
hnlucky5 小时前
《Zabbix Proxy分布式监控实战:从安装到配置全解析》
数据库·分布式·学习·adb·zabbix·集成学习·proxy模式