Spring事务传播级别

汇总表

使用场景

PROPAGATION_REQUIRED

如果嵌套执行的方法要求一起执行成功或者一起回滚,则选择该事物传播级别。

PROPAGATION_REQUIRED_NEW

如果嵌套执行的方法要求各自事务独立,不能进行相互影响,则选择本事务传播级别。

PROPAGATION_SUPPORTS

如果嵌套执行的方法要求一起执行成功或者一起回滚,单独执行时候以非事务方式执行,则选择该事物传播级别。

PROPAGATION_NOT_SUPPORTED

如果嵌套执行的方法要求内部嵌套方法不会对外部方法事务造成影响并且内部方法不需要事务,单独执行时候以非事务方式执行,则选择该事物传播级别。

PROPAGATION_MANDATORY

如果嵌套执行的方法要求一起执行成功或者一起回滚,单独执行时候不允许以非事务方式执行,则选择该事物传播级别。

PROPAGATION_NEVER

如果嵌套执行的方法要求内部方法不允许在事务中执行,单独执行时候必须以非事务方式执行,则选择该事物传播级别。

PROPAGATION_NESTED

如果嵌套执行的方法要求内部方法出错只回滚自己,外部方法执行失败回滚所有,单独执行时候自动开启一个执行,则选择该事物传播级别。

踩过的坑

我写了一个代码

1
2
3
4
5
6
7
8
9
@Transactional(rollbackFor = Exception.class)
public SomeThing action() {
// 无事务注解,该方法匹配上了xml配置文件中的"method*"
// 向数据表 X 中插入数据
methodA();
// 无事务注解,一定条件下会查询 X 表中的数据,当然也包含 methodA 插进去的
actionB();
return something;
}

当 actionB 方法查询 X 表数据时,死活查不到 methodA 刚刚插入的数据,对 sql 语句的检查也没发现问题,日志显示也确实执行了插入操作。我理解这三个方法应该都在一个事务里,即 action 创建的这个事务(Spring 默认传播级别为 required)

后来在项目中的事务配置xml文件中发现这么一个配置:

1
2
3
4
<!--            其他代码             -->
<tx:method name="method*" rollback-for="Exception" propagation="REQUIRED"/>
<tx:method name="*" propagation="NOT_SUPPORTED"/>
<!-- 其他代码 -->

导致执行过程中, action 和 methodA 在同一个事务里,actionB 并不在这个事务里,action 没有执行到 return something; 事务就没有提交,导致 actionB 的查询操作读取不到 methodA 插入的数据。

因此,需要了解各个事务传播级别的特性及影响,对事务传播级别进行配置的时候也要考虑这些特性带来的影响,以免给自己或他人造成不必要的麻烦。


Spring事务传播级别
https://www.llimmy.top/2021/03/22/Spring事务传播级别/
作者
Limmy
发布于
2021年3月22日
许可协议