首先我们知道,spring的事务管理有以下几种事务属性: PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED 类似的操作。 ======================= 针对这些事务属性,我做了几次试验。 使用的代码简单描述就是: 外层方法{ try{ 内层方法();}catch(RuntimeException e){} } 内层方法(){ 抛出 RuntimeException ; } ======================= 对REQUIRED的试验时,配置是: <tx:method name="外层方法" propagation="REQUIRED" /> <tx:method name="内层方法" propagation="REQUIRED" /> 在日志中看到: 1、为外层方法创建事务
- Creating new transaction with name [外层方 法]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2、为内层方法配置事务
- Participating in existing transaction
可以看到 ,内层方法使用的是外层方法的事务上下文。然后,当内层方法抛出异常时,日志中记录:
Setting JDBC transaction [...] rollback-only 即要求该事务回滚。但是内层方法的异常被外层方法捕获并处理了, 外层方法仍然会继续执行,并在执行完毕后提交事务。这时日志中记录并抛出异常:
Global transaction is marked as rollback-only but transactional code requested commit
(执行事务回滚...)
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
所谓 “支持当前事务” , 就是在当前事务的上下文内执行目标方法。 内层方法对事务的操作会影响到外层方法。
=========================
对 NESTED 的试验时,配置如下:
<tx:method name="外层方法" propagation="REQUIRED" /> <tx:method name="内层方法" propagation="NESTED" />
在日志中看到:
1、为外层方法创建事务
- Creating new transaction with name [外层方 法]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2、为内层方法创建嵌套事务
- Creating nested transaction with name [ 内层方法 ]
1、 内层方法回滚、提交
- Rolling back transaction to savepoint
2、 外层方法继续执行并提交
外层方法逻辑输出
- Triggering beforeCommit synchronization
……
可见,嵌套事务与当前事务可以认为是两个事务,只是它不会挂起当前事务。嵌套事务即使回滚,当前事务仍然可以正常提交。
=======================
对SUPPORTS试验时, 使用的配置是:
<tx:method name="外层方法" propagation="SUPPORTS" /> <tx:method name="内层方法" propagation=" REQUIRED " />
另外内层方法改为了:
内层方法(){ return; } 这种方案下,日志中只有为内层方法创建事务的记录,对外层方法基本是“不闻不问”的。而如果把配置反过来,改成
<tx:method name="外层方法" propagation=" REQUIRED " /> <tx:method name="内层方法" propagation="SUPPORTS" />
那么, spring会为外层方法创建事务,而对内存方法则使用外层方法的事务上下文。
但是,如果配置为:
<tx:method name="外层方法" propagation="SUPPORTS" /> <tx:method name="内层方法" propagation="SUPPORTS" />
日志中会出现几行这样的记录:
Triggering beforeCommit synchronization
Triggering beforeCompletion synchronization
Triggering afterCommit synchronization
Triggering afterCompletion synchronization
这些是事务提交前后的日志;但是却找不到创建事务相关的日志。我不清楚为什么会出现这种事务前后行为不匹配的情况。以后再琢磨琢磨吧。
======================
其它的几种情况我没有再测试了。不过,事务相关配置的基本含义到这里差不多已经清楚了,其它的情况可以“同理可证”或者“由此推知”了吧。