• 【JavaEE】Spring 事务传播机制


    1. 事务传播机制定义

    Spring 事务传播机制定义了多个包含了事务的⽅法,相互调⽤时,事务是如何在这些⽅法间进⾏传递的。

    1.1 事务传播机制与事务隔离级别区别

    • 事务隔离级别是保证多个并发事务执⾏的可控性的(稳定性的)(横向并列时)
    • 事务传播机制是保证⼀个事务在多个调⽤⽅法间的可控性的(稳定性的)(纵向相互调用时)

    事务隔离级别解决的是多个事务同时调⽤⼀个数据库的问题,如下图所示:
    在这里插入图片描述
    ⽽事务传播机制解决的是⼀个事务在多个节点(⽅法)中传递的问题,如下图所示:
    在这里插入图片描述
    在这里插入图片描述

    2. 7大事务的传播机制

    Spring 事务传播机制包含以下 7 种:
    在这里插入图片描述

    1. Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。(整体考虑,局部事务出问题,整体都回滚)
    2. Propagation.SUPPORTS:如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。
    3. Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加⼊该事务;如果当前没有事务,则抛出异常。
    4. Propagation.REQUIRES_NEW:表示创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部⽅法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部⽅法会新开启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰。
    5. Propagation.NOT_SUPPORTED:以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。
    6. Propagation.NEVER:以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。
    7. Propagation.NESTED:如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。(局部考虑,局部事务出问题,只回滚这个局部事务,这个局部事务不会导致整体事务回滚)

    以上 7 种传播⾏为,可以根据是否⽀持当前事务分为以下 3 类:
    在这里插入图片描述
    以上分类可以用“情侣”关系来帮助理解:
    在这里插入图片描述

    3. Spring 事务传播机制使用和各种场景演示

    关靠以上理论理解事务困难很多,接下来就以实际场景(代码演示)为列来讲解spring事务的传播机制使用,帮助大家更好的理解并正确使用事务的7大传播机制:

    3.1 支持当前事务(REQUIRED)

    首先在数据库中建立两个表(user表+log表)用户表和日志记录表,来演示事务的传播机制使用:

    在这里插入图片描述
    在这里插入图片描述
    以及这两个表对应的Java实体类(model):
    在这里插入图片描述
    在这里插入图片描述
    实现添加用户和添加日志的mapper和xml:
    添加用户:
    在这里插入图片描述
    在这里插入图片描述
    添加日志:
    在这里插入图片描述
    在这里插入图片描述
    注意在写添加日志SQL时候由于表字段desc与mysql关键字desc冲突,所以要给SQL desc加上 `` 反引号(esc键下面的那个)

    此时的代码调用关系如下图:
    在controller中的add接口先是调用添加用户的userservice接口,在添加用户完成后调用添加日志的logservice接口(在service层调用mapper来实现SQL操作数据库):
    在这里插入图片描述
    service层代码如下:
    在这里插入图片描述
    在这里插入图片描述

    此时测试 REQUIRED :
    controller层代码:
    在这里插入图片描述
    给service层分别实现添加用户和添加日志的两个方法也加上此传播机制(不加也一样,默认的事务传播机制):
    在这里插入图片描述
    在这里插入图片描述

    访问接口:(传递用户的姓名和密码)
    注意此时数据库中user表只有admin默认这一个记录,日志表为空:
    在这里插入图片描述
    在这里插入图片描述
    代码不出所料触发了在添加日志代码时的异常:在这里插入图片描述
    此时观察控制台:
    在这里插入图片描述
    发现添加用户以及添加日志的SQL均执行成功
    但是,观察数据库:
    在这里插入图片描述
    用户表和日志表中依旧没有刚才执行的SQL结果,也就是说事务全部都回滚了!

    ⽤户表和⽇志表中都没有添加任何数据,说明整个事务都回滚了。也就是说 REQUIRED 如果回滚就是
    回滚所有事务,不能实现部分事务的回滚。

    总结:加入当前事务 @Transactional(propagation = Propagation.REQUIRED)
    当日志添加方法出现异常之后,加入事务的执行结果是:

    • 用户添加成功的数据也跟着回滚了
    • 日志添加数据自然也回滚了

    3.2 NESTED 嵌套事务

    此时在controller代码中使用嵌套事务:
    在这里插入图片描述
    在service中添加用户和添加日志的方法上也设置嵌套事务:
    在这里插入图片描述
    在这里插入图片描述
    此时依旧在添加日志时候触发异常使事务回滚:
    访问接口:
    在这里插入图片描述
    SQL也是执行成功的:
    在这里插入图片描述

    结果和上面的 REQUIRED 现象是一样的,此时我们观察数据库:
    在这里插入图片描述
    发现user表用户插入成功了,但是日志表日志依旧没有插入成功

    总结:
    嵌套事务: @Transactional(propagation = Propagation.NESTED)
    当日志添加方法出现异常后,嵌套事务的执行结果是:

    • 用户添加不受影响,添加用户成功了,添加用户事务没有回滚
    • 日志添加失败了,发生了异常回滚了日志添加的事务

    所以说 required 加入事务,局部事务的失败是影响整体事务的,局部失败导致整体也失败
    nested 嵌套事务,局部事务的失败只影响局部事务,只会回滚局部事务,其他事务不会影响

    嵌套事务只所以能够实现部分事务的回滚,是因为事务中有⼀个保存点(savepoint)的概念,嵌套事务
    进⼊之后相当于新建了⼀个保存点,⽽滚回时只回滚到当前保存点,因此之前的事务是不受影响的,这
    ⼀点可以在 MySQL 的官⽅⽂档汇总找到相应的资料:savepoint官网文档
    (相当于玩单机游戏时候的存单点(保存点savepoint),如果玩家死亡(代码异常)就会自动回到上一个存档点,所以嵌套事务能实现部分事务的回滚)
    在这里插入图片描述
    REQUIRED 是加⼊到当前事务中,并没有创建事务的保存点,因此出现了回滚就是整个事务回滚,这就是嵌套事务和加⼊事务的区别。

    总结:嵌套事务(NESTED)和加⼊事务(REQUIRED )的区别:

    • 整个事务如果全部执⾏成功,⼆者的结果是⼀样的。
    • 如果事务执⾏到⼀半失败了,那么加⼊事务整个事务会全部回滚;⽽嵌套事务会局部回滚,不会影
      响上⼀个⽅法中执⾏的结果。

    3.3 不支持当前事务(REQUIRES_NEW)

    UserController 类中的代码不变,将添加⽤户和添加⽇志的⽅法修改为 REQUIRES_NEW 不⽀持当前事
    务,重新创建事务,观察执⾏结果:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    注意这里添加日志的代码是先触发异常,再执行添加:
    在这里插入图片描述
    程序执⾏结果:User 表中成功插⼊了数据,Log 表执⾏失败,但没影响 UserController 中的事务。

    结论:不管外部⽅法(controller/add)是否开启事务,Propagation.REQUIRES_NEW 修饰的内部⽅法(添加用户和添加日志)会新开启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰。

    3.4 不支持当前事务,NEVER 抛异常(存在事务,则抛出异常)

    在service中设置此事务传播机制,则只要调用链中存在事务,就抛出异常,代码也不会执行成功的:
    在这里插入图片描述
    在这里插入图片描述
    直接抛异常,数据库中也没有相应记录:
    在这里插入图片描述

    • over ~ ✨
  • 相关阅读:
    java培训技术ModelAttribute注解修饰POJO类型的入参
    unity学习(46)——服务器三次注册限制以及数据库化角色信息1--数据流程
    【数据结构和算法初阶(C语言)】链表-单链表(手撕详讲单链表增删查改)
    JOSEF约瑟 10KV高压漏电保护继电器BLD-20 φ100mm 50-500mA 导轨安装
    栈和队列知识点+例题
    浅谈Array --JavaScript内置对象
    Hamiton图系列文章 (1) Hamilton图证明算法的道路矩阵基础数据结构与类的设计
    SpringBoot单元测试
    门控时钟介绍
    CentOS 7 安装新版本的Nginx
  • 原文地址:https://blog.csdn.net/xqs196301/article/details/126733144