• Spring事务的嵌套的详细理解,以及事务失效的场景解惑


    Spring事务的的详细理解,事务嵌套解析,以及事务失效的场景解惑

    想要了解Spring的事务嵌套,我们先了解一下Spring的七种事务传播属性各自表示的意思

    1、propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
    2、propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
    3、propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
    4、propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
    5、propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    6、propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
    7、propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作

    了解了这七种传播属性表示的意思,接下来在说具体的解释

    详解Spring的事务传播属性以及在写代码的过程中发生嵌套并发生事务失效的场景

    再说这些之前,大家先要清除一个问题,Spring的事务是怎么实现的?
    Spring本身是没有事务的,只有数据库才会回有事务,而Spring的事务是借助AOP,通过动态代理的方式,在我们要操作数据库的是时候,实际是Spring通过动态代理进行功能扩展,在我们的代码操作数据库之前通过数据库客户端打开数据库事务,如果代码执行完毕没有异常信息或者是没有Spring要捕获的异常信息时,再通过数据库客户端程序提交事务,如果有异常信息或者是有Spring要捕获的异常信息,再通过数据库客户端程序回滚事务,从而达到控制数据库事务的目的。

    1、Spring的事务的简单原理示意图,请看下图
    在这里插入图片描述
    2、Spring的Transactional注解默认情况下的传播属性是什么呢,请看一下Transactional的源码:下图所示(所以在默认的情况下我们加了Transactional 就会有事务)
    在这里插入图片描述
    3、第1、第2两部分看明白之后,再来说一下Spring事务嵌套会发生的情况
    3.1、在同一个类中发生事务嵌套的情况
    在这里插入图片描述
    答案是会回滚的,原因是什么呢?接着看下边额示意图
    在这里插入图片描述
    看上边的示意图你一定会明白了吧,原因还是因为代理的时候,直接把没有事务的方法包在了有事务的代理方法里边了自然就有事务了,这样说够明确吗?不够的话可以留言,给你解答一下

    3.2 再看一种嵌套的方式
    在这里插入图片描述
    答案:这时候调用test02,test01有异常发生时是不会回滚的
    为什么呢?其实如果上边的你理解了下边就很容易理解了
    在这里插入图片描述
    3.3 这些明白了 后边的就更容易明白了,再看一个例子
    在这里插入图片描述
    上述3.3中的例子,如果调用test02 的话,当程序发生异常,test01会不会回滚呢?

    答案是会回滚的 原因和3.1中的情况类似

    所以综合上边说的,在同一个类中事务嵌套的话,最终的结果应该是取决于最外层的方法事务的传播特性

    4、以上是在一个相同的类中的情况,如果是不同的类中的方法嵌套调用是什么样子的呢?
    4.1 我们来看下列一种情况
    在这里插入图片描述
    在TestService3中调用TestService4中的没有事务的方法,会发生什么呢?TestService4中的test41方法发生异常会回滚吗?

    答案 会的
    为什么呢请看下图:
    在这里插入图片描述
    4.2 我们再来看一个情况
    在这里插入图片描述
    TestService3中的方法是有事务的,TestService4中的方法是以非事务的方式运行,如果存在事务就挂起事务,那么自然就没有事物了
    所以上述的情况就是,如果TestService4中的方法报出异常,则TestService3中的数据可以回滚,但是TestService4中操作的数据是不会回滚的

    再有其他的情况大家根据上述的原理,然后结合传播属性的特点去套就可以了

    总结4中的案例得到的结论是,如果是不同的类的事务嵌套的话,外层的方法按照外层的事务传播属性执行,内层的传播属性按照内层的传播属性的特点去运行

    5、下边介绍一些目前我知道的Spring事务会失效的情况
    5.1 事务方法访问修饰符不是public,导致事务失效
    比如 下图
    中的代码在这里插入图片描述
    解释,其实如果是JDK的动态代理 就不允许这种情况,因为JDK动态代理需要有接口,而接口中是不能有 私有方法的,如果是CGLIB动态代理的话也是不允许的代理private方法的

    5.2 如果事务方法是static、final的,同样无法通过动态代理,事务也是不会生效的。Spring的声明式事务是基于动态代理实现的,我们无法重写final修饰的方法;不管是JDK动态代理还是Cglib的动态代理,就是要通过代理的方式获取到代理的具体对象,而static方法修饰的方法是属于类对象的,不属于任何实例对象,所以static方法不能被重写也就是说static方法也不被进行动态代理。

    5.3 如下图中所示 @Transactional注解的方法抛出的异常不是注解中配置的spring的事务支持的异常,导致事务失效
    在这里插入图片描述
    5.4 操作的数据库表如果本身不支持事务 那么配置的Spring事务 也会失效

    5.6 代码中的异常被 catch 住,而且没有异常再次抛出,也会让spring的事务失效,如下图中所示 事务就会失效在这里插入图片描述
    想要 避免上述的失效的话 可以 在catch 住后在catch块中再次 抛出Spring事务支持的异常,就可以了

    5.7 多线程的调用导致事务的失效,例如 下边的案例 会导致 test31的事务失效
    在这里插入图片描述
    解释:原因是因为 test31中操作数据库的链接,test41在线程中操作的时候获取的数据库链接不是同一个数据库连接导致的事务失效,因为同一个事务中的数据库连接必须是同一个才可以保证同时提交和回滚,否则的话如果连接不一样,对应的数据库事务都是不同的事务,自然不能保证同时回滚或者提交了。

    (上述的案例代码都经过验证,大家放心使用,发现有问题请动一下可爱的手指留下言哦)

    好了,写了这么多希望可以帮到各位,觉得不错的话 记得点个赞哦。

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    K8s为何需要Pod
    小企业财务软件哪个最好用,该如何选择?
    【视觉检测】电源线圈上的导线弯直与否视觉检测系统软硬件方案
    JNA嵌套结构体,如何访问内嵌结构体的成员?
    【python爬虫】——历史天气信息爬取
    交叉验证Cross Validation
    SPARK中的wholeStageCodegen全代码生成--以aggregate代码生成为例说起(5)
    GET和POST请求的区别
    NIO和BIO
    前端使用 Konva 实现可视化设计器(6)- 复制粘贴、删除、位置、zIndex调整
  • 原文地址:https://blog.csdn.net/m0_67393593/article/details/126116852