Spring事务传播属性介绍(一).required 和 reuqires_new
Mandatory、Never、Not_Support传播属性分析传送门:https://www.cnblogs.com/lvbinbin2yujie/p/10260030.html
Nested传播属性分析传送门:https://www.cnblogs.com/lvbinbin2yujie/p/10260066.html
我的Spring事务传播属性介绍比较传送门:https://files.cnblogs.com/files/lvbinbin2yujie/Spring_Tx_Note.rar
最近查看了Spring事务源码,是4.2.x的版本还是4.3.x的版本,简单了解了一些事务的概念,介绍下我对Spring事务源码的分析.
Spring一共七种事务传播属性,本文先来作为开篇介绍。
REQUIRED事务,Spring Transactional注解默认的事务,需要该方法在有事务情况下运行,如果当前没有事务就新建一个事物;
REQUIRES_NEW事务,当前方法运行没有事务,新建一个事物,当前方法有事务将当前事务挂起,新事物执行完毕再恢复原有事务;
这里提一点.,以前不明白什么是同一事务核心是什么,后来看到有位仁兄介绍,同一事务的事务信息、事务状态对象不同,但是底层是同一个Connection对象;这点我深以为.
实验说明环节
包结构:

Spring配置文件: (简单介绍下, 定义了一个数据源、DataSourceTransactionManager;此外tx:annotation-driven作用是用来启用Transactional注解的)

ServiceA.java文件

ServiceB.java文件

测试Main方法:

PROPAGATION_REQUIRED
说明: 默认的事务级别, 需要事务;如果当前没有事务,则创建新的事务;如果有事务呢,就加入当前的事务;
如果所有的Transactional标签都是默认的,REQUIRED时,方法里的提交、回滚都是一起的,要么所有都提交,要么所有都回滚;一荣俱荣,一损俱损;
查看源码时候打印事务的日志:

查看输出结果: 可以看到 确实提交了,并且加入了之前的事务,加入之前事务就是共用的一个Connection对象;

情景二: 修改ServiceB的addUser方法 来模拟调用其他业务方法时候执行抛出运行时异常; (同时将数据库之前测试结果 删除,便于观察)

先查看结果: 艾尼路记录添加进来又回退了, 查看日志:

说明: addUser抛出类型为RuntimeException类型的异常,callB捕获该异常之后,发现addUser在事物callB中,于是将事务状态DefaultTransactionStatus对戏中的事务对象DataSourceTransactionObject中的ConnectionHolder对象,即持有底层Connection的对象,将ConnectionHolder标记为rollbackOnly为true,然后将异常抛给调用addUser的callB方法;
在callB调用时根据Spring事务回滚规则,决定回滚操作;因为在情景二同一个事务中ConnectionHolder中持有的Connection对象是同一个,所以callB方法整个回滚了;
情景三: callB方法中手动try-catch来捕获异常会发生什么呢?
修改ServiceA的callB方法(为了便于观察,不输出异常,只是简单打印)

直接查看输出日志(最后一行抛出的异常排版原因未截全): 查看日志,记录确实添加了但是又回滚过了,数据库里没有记录。
异常信息:
Exception in thread "main" org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

说明: callB作为事务的开始,addUser作为事务的一部分,addUser抛出异常以后将ConnectionHolder对象的rollbackOnly设置为true,标记为需要回滚,但是执行完callB方法,没有抛出异常,就认为应该正常提交; 提交之前会校验两次,有一次是 Global transaction is marked as rollback-only but transactional code requested commit;
意思是全局事务需要回滚操作,但是事务代码现在要提交,这时候Spring还是会回滚;(通俗点就是addUser方法需要回滚,但是callB方法没有发生预料之外的异常,因为异常自己手动捕获,这时候Spring还是会回滚);
callB和ServiceB的事务信息对象TransactionInfo是不一样的,其属性事务状态TransactionStatus也不是同一个对象,TransactionStatus的底层事务对象transaction也不是同一个对象,transaction持有ConnectionHolder对象的Connection确实同一个,这样就保证了可以使用Connection对象来保持事务的一致性,一起提交、一起回滚; 保证两个Connection是同一个对象的是ThreadLocal,TransactionSynchronizationManager的resources里存放了着;
总结: REQUIRED不建议手动捕获异常,会破坏Spring的事务规则;try-catch需要结合传播类型,再决定使用与否;
PROPAGATION_REQUIRES_NEW
说明: 创建新的事务并执行,如果当前有事务,那将当前事务挂起,新建一个事物;
给ServiceA类callB方法修改下:

ServiceB类添加方法addUserFail,事务属性设置为REQUIRE_NEW

正常情况下查看输出日志:
可以发现,当进入REQUIRED_NEW事务里的方法时,挂起了原来的事务,事务执行完毕恢复了事务;并且外层事务和addUserFail事务是分别提交的;

情景三.
ServiceA方法:

ServiceB方法:

测试类方法:

说明:callB2方法调用了ServiceB的两个事务方法,ddUserSuccess方法是REQUIRED事务,addUserFail方法是REQUIRED_NEW事务,按照之前分析的,REQUIRED_NEW的方法是一个新的事务,那我抛出异常自己就会回滚,不应该干扰到callB2方法的回滚;
执行结果: addUserSuccess方法被带着一起回滚了,即外层事务也被带着一起回滚了;
查看源码发现: addUserFail的确新建了事务,然后抛出异常之后,着手回滚,回滚完成后将异常throw了,异常被throw那就会丢给调用addUserFail的地方,没错,丢到了callB2方法里,那callB2也着火了,发生异常,这时候callB2的事务也被认定为执行失败应当回滚,那callB2的事务就开始回滚,callB2内部事务addUserSuccess回滚, 所以一条记录都没有写进去.
(想了下,REQUIRED_NEW事务的方法就在调用他的地方手动捕获异常,不让异常向上传递了,这样就能达到目的,且不会像REQUIRED一样报异常)
简单画了如下例子,外层事务为REQUIRED类型;外层事务有两个方法,A、B;Spring默认回滚规则为RuntimeException或Error类型,下面例子抛出异常也是RumtimeException或Error类型,且没有手动try-catch捕获异常;

Spring事务传播属性介绍(一).required 和 reuqires_new的更多相关文章
- Spring事务传播属性介绍(二).mandatory、not_supported、never、supports
Required.Required_New传播属性分析传送门:https://www.cnblogs.com/lvbinbin2yujie/p/10259897.html Nested传播属性分析传送 ...
- Spring事务传播属性介绍(三).Nested
Required.Required_New传播属性分析传送门:https://www.cnblogs.com/lvbinbin2yujie/p/10259897.html Mandatory.Neve ...
- spring事务传播机制实例讲解
http://kingj.iteye.com/blog/1680350 spring事务传播机制实例讲解 博客分类: spring java历险 天温习spring的事务处理机制,总结 ...
- Spring事务传播机制和数据库隔离级别
Spring事务传播机制和数据库隔离级别 转载 2010年06月26日 10:52:00 标签: spring / 数据库 / exception / token / transactions / s ...
- spring 事务传播机制
spring 事务 传播机制 描述的 事务方法直接相互调用,父子事物开启,挂起,回滚 等的处理方式. 绿色的 那几个 我认为比较重要. 1 , @Transactional(propagation=P ...
- spring 事务传播行为实例分析
Spring事务传播行为: spring特有的事务传播行为,spring支持7种事务传播行为,确定客户端和被调用端的事务边界(说得通俗一点就是多个具有事务控制的service的相互调用时所形成的复杂的 ...
- Spring事务传播机制与隔离级别(转)
Spring事务传播机制与隔离级别 博客分类: Spring 转自:http://blog.csdn.net/edward0830ly/article/details/7569954 (写的不错) ...
- Spring 事务传播行为的使用
...
- spring事务传播特性实验(2):PROPAGATION_REQUIRED实验结果与分析
本文延续上一文章(spring事务传播特性实验(1):数据准备),在已经准备好环境的情况下,做如下的实验,以验证spring传播特性,加深对spring传播特性的理解. 本次主要验证PROPAGATI ...
随机推荐
- RxSwift学习笔记3:生命周期/订阅
有了 Observable,我们还要使用 subscribe() 方法来订阅它,接收它发出的 Event. let observal = Observable.of("a",&qu ...
- NFS Server宕机后,NFS Client主机上df命令挂死
方法1: 使用root用户:Oracle@NDMCDB05:~> su -Password: NDMCDB05:~ # cat /etc/mtab /dev/sda2 / reiserfs rw ...
- 电子书推荐--《Python灰帽子》,python黑客编程
点此在线阅读 <Python灰帽子>是由知名安全机构Immunity Inc的资深黑帽Justin Seitz主笔撰写的一本关于编程语言Python如何被广泛应用于黑客与逆向工程领域的书籍 ...
- TextBox Ctrl+A不能全选的问题
问题: 当TextBox控件在设置了MultiLine=True之后,Ctrl+A 无法全选,十分影响使用体验. 对于这个问题不明所以,不知道是Bug,还是故意而为之... 解决1: 添加KeyDow ...
- Linux系统磁盘与分区管理(7)
Linux最传统的磁盘文件系统(filesystem)使用的是EXT4格式,所以要了解文件系统就得要由认识EXT4开始,而文件系统是创建在硬盘上面的,因此我们得了解硬盘的物理组成才行,下面我们回来详细 ...
- 实现域名访问网站—nginx反向代理
今天在跟项目的时候,是否被耍了三个多小时,最后在我准备号材料准备他人求助的时候,在收集材料的时候,居然访问通了, 别问我为什么,我也不知道 ,哈哈哈哈(苦逼脸...) 分享出来,大家共同学习: 这个是 ...
- Redis---SDS(简单动态字符串)
Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串), 而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类 ...
- ThinkPHP5代码执行的简单分析
漏洞影响版本: ThinkPHP 5.0.5-5.0.22 ThinkPHP 5.1.0-5.1.30 漏洞复现: 一.mac的debug环境搭建. 一键化环境搭建工具: mamp pro ,调试工具 ...
- github或码云协同开发
协同开发 1.引子:假如三个人共同开发同一份代码,每个人都各自安排了任务,当每个人都完成了一半的时候,提交不提交呢? 要提交,提交到dev吗,都上传了一半,这样回家拿出来的代码根本跑不起来.所以, 为 ...
- POJ 2492
#include<iostream> #include<stdio.h> #define MAXN 2050 using namespace std; int pre[MAXN ...