Spring 嵌套事务提交时机对其他查询操作的影响分析

887 阅读2分钟

背景

Spring 的 @Transactional 注解可以轻松实现数据库操作的事务控制,本文介绍上周遇到的一个嵌套事务的问题,探讨嵌套事务的提交时机对后续操作的影响。

服务调用链上的事务使用

一个调用链上,方法 A 调用了方法 B ,方法 A 和 B 中同时存在数据库操作,大概伪代码如下:

public void A() {
  1、数据库查询
  2、数据库插入
  3、调用方法 B
  4、B(); // 另一个类的方法
  5、 数据库查询:查询方法 B 插入的数据
  6、 数据库操作:删除方法 B 插入的数据
}

public void B {
}

这里讨论事务注解添加的位置,对操作步骤5 和 6 的影响。

情况一:只在 A 上加事务,所有操作在同一个事务中,操作步骤5 和 6 的数据依赖 4 的数据,而且数据是一致的。@Transactional 注解标注的流程中,所有 DAO 的操作在同一个事务中,对于 Propagation.REQUIRES_NEW 的事务来说,前面的数据库写操作,对后面的读操作是可见的。

情况二:A 和 B 上都有事务,步骤4调用 B 方法后向某表插入了数据,5 再查询查不到,但是 6 删除时有删除记录,说明 B 方法的事务的提交是在写操作时提交的。此时,要想让 步骤 5 立即读取到方法 B 插入的数据,可以修改 SQL 加上 for update 强制提交。

情况三:B 上没用事务注解,而是用 TransactionTemplate 手动提交插入操作,那么后面操作数据也能保持一致。

启示录

之所以在方法 B 上添加新事务,是为了不让方法 B 的操作受到方法 A 的异常的影响,但是如果二者数据有查询依赖的话,查询操作不会带来 B 事务的提交,所以造成数据不一致问题。