参考文章:https://segmentfault.com/a/1190000013341344
什么是事务传播机制
官方的解释:在一个事务的范围内的操作将会成为事务的一部分并且在这个事务中执行。但是,如果已经存在一个事务的环境,也可以改变一个在该环境中带有事务属性方法的行为。比如:这个带事务属性的方法可以在已经存在的事务中执行操作,它也可以再新开启一个事务在这个新开启的事务中执行操作。
我个人的理解:Propagation定义了一个带有事务属性的里层方法在被另一个带有事务属性的外层方法调用时,里层方法将以什么样的形式去执行操作。
比如下面的代码块中:methodA和methodB都开启了事务,methodA中调用了methodB。是应该把methodA和methodB看成同一个事务进行操作(methodA与methodB会互相影响)?还是methodA和methodB各自使用了不同的事务,二者互不影响?这就与@Transactional中的传播机制Propagation属性相关了。
@Transactional
methodA(){
...操作...
@Transactional
methodB();
}
Propagation可以取的值:
测试准备
主要使用的方法:
- 里层方法异常,自己捕获处理(try catch),不被外层方法感知;
- 里层方法异常委托给外层方法来处理;
- 外层方法异常。
测试Propagation
REQUIRED
REQUIRED为Propagation属性默认的值
-
外层方法不开启事务,两个里层方法开启事务并设置传播机制为REQUIRED,其中一个方法会抛出异常:无异常的执行成功,有异常的回滚
-
外层方法开启事务,两个里层方法开启事务并设置传播机制为REQUIRED,其中一个方法会抛出异常:两个里层方法的事务均回滚
-
外层方法开启事务,两个里层方法开启事务并设置传播机制为REQUIRED,其中一个方法会抛出异常但是这个方法自己使用try catch捕获了这个异常:两个里层方法的事务均回滚。
-
外层方法开启事务,里层方法开启事务并设置传播机制为REQUIRED,外层方法抛出异常:里层方法回滚
总结:如果外层未开启,里层方法的事务互不干扰;外层开启了事务,里层外层使用同一个事务
REQUIRED_NEW
-
外层方法不开启事务,两个里层方法开启事务并设置传播机制为REQUIRED_NEW,其中一个方法会抛出异常:无异常的执行成功,有异常的回滚
-
外层方法开启事务,两个里层方法开启事务并设置传播机制为REQUIRED_NEW,其中一个方法会抛出异常:无异常的执行成功,有异常的回滚
-
外层方法开启事务,一个里层方法开启事务并设置传播机制为REQUIRED,另一个设置为REQUIRED_NEW, 外层方法抛出异常:传播机制为REQUIRED的里层方法回滚,另一个REQUIRED_NEW的正常执行
总结:无论外层方法开不开启事务,里层方法都会自己创建一个新的事务去执行与其他的事务(外层,其他里层的事务)互不干扰
NESTED
-
外层方法不开启事务,两个里层方法开启事务并设置传播机制为NESTED,其中一个方法会抛出异常:无异常的执行成功,有异常的回滚
-
外层方法开启事务,两个里层方法开启事务并设置传播机制为NESTED,其中一个方法会抛出异常:两个里层方法的事务均回滚
-
外层方法开启事务,两个里层方法开启事务并设置传播机制为NESTED,其中一个方法会抛出异常但是这个方法自己使用try catch捕获了这个异常:未抛出异常的执行成功,抛出异常的回滚
-
外层方法开启事务,里层方法开启事务并设置传播机制为NESTED,外层方法抛出异常:里层方法回滚
总结:如果外层开启了事务,里层外层使用同一个事务,外层事务回滚子事务也会滚,子事务的异常未被外层事务感知则外层事务不会回滚;
外层未开启事务,子事务间互不影响
我总结的不够好,可以看看这个博主的,我把截图放在下面了
https://segmentfault.com/a/1190000013341344
MANDATORY
- 外层方法不开启事务,里层方法开启事务并设置传播机制为MANDATORY:结果抛出异常
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’ - 外层方法开启事务,里层方法开启事务并设置传播机制为MANDATORY:插入成功
- 外层方法开启事务,两个里层方法开启事务并设置传播机制为MANDATORY,其中一个里层方法抛出异常:两个里层方法的事务均回滚
- 外层方法开启事务,两个里层方法开启事务并设置传播机制为MANDATORY,其中一个里层方法抛出异常并自己try catch 捕获:两个里层方法的事务均回滚
总结:外层方法必须开启事务,否则抛出IllegalTransactionStateException异常。外层方法和里层方法使用同一个事务
SUPPORTS
-
外层方法不开启事务,两个里层方法开启事务并设置传播机制为SUPPORTS,其中一个方法会抛出异常:两个方法互不影响,抛出异常的方法没有影响到另一个方法
-
外层方法开启事务,两个里层方法开启事务并设置传播机制为SUPPORTS,其中一个方法会抛出异常:正常的方法也回滚了
-
外层方法开启事务,两个里层方法开启事务并设置传播机制为SUPPORTS,其中一个方法会抛出异常但是这个方法自己使用try catch捕获了这个异常:正常的方法也回滚了
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
总结:如果外层方法开启事务,外层方法和里层方法使用同一个事务;
如果未开启,均以非事务的形式执行
NOT_SUPPORTED
- 外层方法开启事务,里层方法开启事务并设置传播机制为NOT_SUPPORTED,外层方法抛出异常:里层方法正常执行,里层方法和外层方法互不干扰
- 外层方法开启事务,两个里层方法开启事务并设置传播机制为NOT_SUPPORTED,其中一个方法会抛出异常:两个里层方法均可执行,出现异常的方法也未回滚
总结:以非事务的形式执行,外层开启了事务则挂起不抛出异常
NEVER
-
外层方法不开启事务,两个里层方法开启事务并设置传播机制为NEVER,并且其中一个里层方法抛出异常:两个里层执行成功,出现异常的里层方法并未回滚
-
外层方法开启事务,里层方法开启事务并设置传播机制为NEVER:里层方法未执行抛出异常
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’
总结:里层方法以非事务的形式执行,外层方法必须开不启事务,否则抛出IllegalTransactionStateException异常
总结
外层不开启事务,里层事务互不干扰;
不使用事务会抛出异常的:NEVER;
使用事务会抛出异常的: MANDATORY;
使用事务不会抛出异常的:NOT_SUPPORT;
可以使用事务也可以不使用事务的:SUPPORT(但是外层开启事务里层如果出现异常并自己捕获,所有里层方法均回滚并会抛出异常);
外层里层使用同一个事务,不管哪里出现异常都会回滚的:REQUIRED;
外层里层使用同一个事务,外层异常里层一起回滚,里层异常并且如果不被外层感知,外层不会回滚的:NESTED;
外层里层使用不同事务:REQUIRED_NEW。