zoukankan      html  css  js  c++  java
  • spring 事务传播行为之嵌套事务NESTED细节

    照抄自:https://www.jianshu.com/p/c6d4095f5833

    spring 事务传播行为之嵌套事务NESTED细节

    经过我之前的实践,可以看出 NESTED事务申明在调用者上会新建一个独立事务。申明在被调用者上,若调用者存在事务则加入调用者事务。调用者不存在事务则新建一个独立事务。

    这个功能好像和spring默认的事务传播行为REQUIRED一样的?
    不,它的功能可是比REQUIRED要强大!

    我来通过实验证明NESTED和REQUIRED的区别

    这个例子是基于 https://www.jianshu.com/p/bc3cbacf9e70 这个文章的代码

    首先,InsertUsers和InsertCuser方法上都申明了REQUIRED,让他们属于同一个事务。将引发异常的语句 int i = 1/0; 放到 InsertCuser方法里

        
      
    注意 为什么要加try/catch包裹cuserService.InsertCuser(cuser);语句?

    为了杜绝InsertCuser中抛出的异常影响InsertUsers方法的实验结果

    try {
                cuserService.InsertCuser(cuser);
            } catch (Exception e) {
                e.printStackTrace();
            }
    

    程序运行,结果是InsertCuser中出现异常,导致事务回滚、users表和cuser表均无数据插入。由于两个方法被纳入同一个事务,因此两者都会回滚。即使在cuserService.InsertCuser(cuser);上使用try/catch捕获并不抛出异常也没用(此方法能保证调用者方法中的独立事务不受被调用者抛出的异常影响而回滚)

    我们再来看,将上面环境的InsertCuser方法传播行为改成NESTED

       

    再次运行,可以看到日志的打印情况。两方法的事务的id一致,说明的确是相同事务

     
    image.png

    users表中插入了数据说明InsertUsers方法提交成功,cuser表中没有数据说明InsertCuser方法回滚

     
    image.png

    那么现在就有一个问题了,既然两个方法使用同一个事务,为什么没有一起回滚?

    这就是NESTED嵌套事务的奥秘之处-----它能让事务部分回滚

    我在网上找到了一句话:

    NESTED申明在被调用方法上,若调用者方法有开启事务。此时NESTED会开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务。 潜套事务开始执行时, 它将取得一个 savepoint。 如果这个嵌套事务失败, 我们将回滚到此 savepoint。 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。

    这段话中提到的 savepoint 其实是mysql的innodb引擎的特性,为了去了解它我在mysql客户端对它进行了简单使用,可以看看这篇文章https://www.jianshu.com/p/c93c1730e5dc 。 总之它就是一个保存点,生成一个保存点就是生成一个数据镜像。然后无论经过了什么sql操作,只要使用回滚至此保存点的命令即可恢复至创建保存点的数据状态。

    那么上面代码的演示结果也就说的通了。即使InsertUsers和InsertCuser方法属于同一个事务,被NESTED嵌套事务申明的InsertCuser方法出现异常也没导致REQUIRED申明的InsertUsers的全部回滚,只是部分回滚到了调用InsertCuser方法之前。因为在调用InsertCuser方法时会自动生成一个savepoint

    InsertUsers方法里出现异常会导致InsertCuser方法嵌套事务回滚吗?

    将出现异常的代码行放到这里,结果都回滚了,毕竟是同一个事务

     
    image.png
    总结下NESTED的回滚特性
    • 主事务和嵌套事务属于同一个事务
    • 嵌套事务出错回滚不会影响到主事务
    • 主事务回滚会将嵌套事务一起回滚了
    进一步证明NESTED嵌套事务的savepoint机制

    可以通过阅读spring源码的方式来验证NESTED是不是使用savepoint机制来实现的,我现在的水平还不足以去阅读源码。但是我会很快就有这个能力的,我相信! 不过有简友已经分析过了,可以去看看。写的很好~
    https://www.jianshu.com/p/2f79ee33c8ad

    如果有来生,要做一片树叶。 春天恋上枝,炎夏恋上水。 深秋恋上土,东来化作泥。 润物细无声,生生世世恋红尘。
  • 相关阅读:
    [置顶] kubernetes资源类型--DaemonSet
    Docker容器的自动化监控实现
    [置顶] docker--基础镜像和dockerfile
    Target runtime Apache Tomcat v8.0 is not defined
    jeecg-org.jeecgframework.web.system.listener.InitListener
    tomcat:利用tomcat部署war包格式的项目
    更换jdk版本:jdk1.8更换为jdk1.7之后输入java -version还是出现1.8的版本号
    Maven项目下WEB-INFO目录下没有编译的classes文件
    解决maven web项目Cannot detect Web Project version. Please specify version of Web Project through...的错误
    如何提高maven的下载速度:享受一下mvn时飞的感觉
  • 原文地址:https://www.cnblogs.com/shujiying/p/14817929.html
Copyright © 2011-2022 走看看