1. 事务传播行为基础认知
从事Java开发这些年,我见过太多因为事务传播行为配置不当导致的业务异常。记得刚入行时接手过一个电商订单系统,用户支付成功后偶尔会出现库存扣减但订单状态未更新的情况,排查三天才发现是@Transactional的propagation参数配错了。这个经历让我深刻意识到,理解Spring事务传播机制绝不是纸上谈兵。
事务传播行为(Transaction Propagation)本质上是解决业务方法嵌套调用时,事务应该如何传递的策略问题。当方法A(已有事务)调用方法B时,方法B是加入A的事务还是新建事务?或者干脆不开启事务?这些都需要通过传播行为来控制。Spring框架提供了7种标准传播策略,每种策略对应不同的业务场景需求。
关键认知:传播行为只对嵌套方法调用有效。如果是单独调用的方法,传播行为设置不会产生任何特殊效果。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 七种传播行为全解析
2.1 REQUIRED(默认值)
这是最常用的传播行为,也是@Transactional注解的默认值。它的逻辑很直观:
- 如果当前存在事务,就加入该事务
- 如果当前没有事务,就新建一个事务
java复制// 订单服务
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(OrderDTO dto) {
orderMapper.insert(dto);
inventoryService.reduceStock(dto.getItems()); // 库存服务也使用REQUIRED
}
当createOrder方法调用reduceStock时,由于createOrder已经开启事务,reduceStock会直接加入这个事务。这意味着如果库存扣减失败,整个订单创建操作都会回滚。这种"同生共死"的特性非常适合订单创建这类强一致性场景。
踩坑记录:曾经在日志记录方法上也用了REQUIRED,导致业务异常时日志也没记录下来。后来明白日志记录应该用REQUIRES_NEW。
2.2 REQUIRES_NEW
这个策略的特点是每次都会新建事务:
- 无论当前是否存在事务,都新建事务
- 新事务与原有事务相互独立,互不干扰
java复制// 支付服务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean processPayment(PaymentRequest request) {
// 支付逻辑
}
在金融交易场景中,支付操作通常需要REQUIRES_NEW。比如用户下单后支付,即使订单创建后续流程失败,支付操作也应该独立提交。但要注意,这会导致事务数量增多,在高并发场景可能成为性能瓶颈。
2.3 NESTED
Spring特有的传播行为,基于保存点(Savepoint)实现:
- 当前存在事务时,在嵌套事务内执行
- 不存在事务时,表现同REQUIRED
- 嵌套事务回滚不会导致外部事务回滚,但外部事务回滚会导致嵌套事务回滚
java复制// 订单服务
@Transactional
public void batchCreateOrders(List<OrderDTO> orders) {
for(OrderDTO order : orders) {
try {
orderService.createOrder(order); // NESTED传播
} catch (Exception e) {
// 单个订单失败不影响其他订单
log.error("订单创建失败", e);
}
}
}
NESTED特别适合批量处理场景,允许部分失败不影响整体。但要注意MySQL的InnoDB引擎才支持保存点,且JDBC驱动版本不能太旧。
2.4 SUPPORTS
随波逐流型传播行为:
- 当前存在事务,就加入
- 当前不存在事务,就以非事务方式执行
java复制// 商品查询服务
@Transactional(propagation = Propa
