spring事务属性的几个试验
基础说明
首先我们知道,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" />
试验结果
默认事务配置
在日志中看到:
- 为外层方法创建事务
- Creating new transaction with name [外层方法]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
- 为内层方法配置事务
- 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事务配置
对NESTED的试验时,配置如下:
<tx:method name="外层方法" propagation="REQUIRED" />
<tx:method name="内层方法" propagation="NESTED" />
在日志中看到:
- 为外层方法创建事务
- Creating new transaction with name [外层方法]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
- 为内层方法创建嵌套事务
- Creating nested transaction with name [内层方法]
- 内层方法回滚、提交
- Rolling back transaction to savepoint
- 外层方法继续执行并提交外层方法逻辑输出
- Triggering beforeCommit synchronization
可见,嵌套事务与当前事务可以认为是两个事务,只是它不会挂起当前事务。嵌套事务即使回滚,当前事务仍然可以正常提交。
SUPPORTS事务配置
对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
这些是事务提交前后的日志;但是却找不到创建事务相关的日志。我不清楚为什么会出现这种事务前后行为不匹配的情况。以后再琢磨琢磨吧。
其它的几种情况我没有再测试了。不过,事务相关配置的基本含义到这里差不多已经清楚了,其它的情况可以“同理可证”或者“由此推知”了吧。