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" />

试验结果

默认事务配置

在日志中看到:

  1. 为外层方法创建事务

- Creating new transaction with name [外层方法]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT

  1. 为内层方法配置事务

- 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" />

在日志中看到:

  1. 为外层方法创建事务

- Creating new transaction with name [外层方法]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT

  1. 为内层方法创建嵌套事务

- Creating nested transaction with name [内层方法]

  1. 内层方法回滚、提交

 - Rolling back transaction to savepoint

  1. 外层方法继续执行并提交外层方法逻辑输出

- 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

这些是事务提交前后的日志;但是却找不到创建事务相关的日志。我不清楚为什么会出现这种事务前后行为不匹配的情况。以后再琢磨琢磨吧。

其它的几种情况我没有再测试了。不过,事务相关配置的基本含义到这里差不多已经清楚了,其它的情况可以“同理可证”或者“由此推知”了吧。