所谓Spring事务的传播属性,就是定义在存在多个事务同时存在的时候,Spring应该如何处理这些事务的行为。这些属性在TransactionDefinition中定义,具体常量的解释见下表:
常量名称 | 常量解释 |
PROPAGATION_REQUIRED |
支持当前事务。 如果当前有事务,则加入当前事务;如果当前没有事务,就新建一个事务。 这是最常见的选择,也是 Spring 事务默认的传播属性。 |
PROPAGATION_REQUIRES_NEW |
新建事务。 即使当前有事务,会额外新建一个事务,新建的事务和原事务相互独立,互不影响。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED |
嵌套事务。 将创建一个依赖于外层事务的子事务,子事务的提交与回滚由外层事务控制,但它无法影响外层事务。当外层事务提交或回滚时,子事务也会连带提交和回滚。 |
具体场景:
假设外层事务 ServiceA 的 methodA() 调用内层 ServiceB 的 methodB()
1、PROPAGATION_REQUIRED
如果serviceA.methodA()与serviceB.methodB()的事务传播属性都定义为PROPAGATION_REQUIRED,Spring会在serviceA.methodA()执行时开启事务,当调用serviceB.methodB()时,会将methodB加入到methodA的事务中,这样两者都在同一个事务下工作,无论methodA还是methodB出现异常,整个事务都会回滚。
2、PROPAGATION_REQUIRES_NEW
如果serviceA.methodA() 为PROPAGATION_REQUIRED,serviceB.methodB() 为PROPAGATION_REQUIRES_NEW,当methodA()开始调用methodB()时,methodA()所在的事务就会挂起,methodB()会开启一个新事务,等methodB()的事务完成以后,methodA()才会继续执行。两者的事务相互独立,互不影响。
3、PROPAGATION_NESTED
如果serviceA.methodA() 为PROPAGATION_REQUIRED,serviceB.methodB() 为PROPAGATION_NESTED,执行逻辑如下:
void methodA() {
try{
serviceB.methodB();
} catch(Exception e) {
// 执行异常情况下的业务逻辑
}
// methodA的相关业务处理
}
当service.methodB()方法出现异常时,methodB的异常会被最外层的methodA捕获,并执行后序的异常处理逻辑以及methodA自身的业务逻辑,最终methodA的事务会正常提交,而methodB的事务会被回滚。
如果methodB正常执行,而后续methodA出现异常,那么methodA和methodB都会回滚。
这就是嵌套事务独有的特性,内层事务的提交与回滚都取决于外层事务。
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于:PROPAGATION_REQUIRES_NEW 将创建一个全新的事务,它和外层事务没有任何关系,而PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务,当外层事务提交或回滚时,子事务也会连带提交和回滚。
其它传播属性不是很常用,这里不过多讨论了。