数据一致性全靠它!Spring 事务传播行为没搞懂=大坑

原文来自于:zha-ge.cn/java/120

数据一致性全靠它!Spring 事务传播行为没搞懂=大坑

昨天和同事聊到一个订单系统的故事,我终于明白为什么"传播行为"这件小事会把数据搞得像过山车。表面上看,事务只是为了让数据要么全成功要么全失败,但在 Spring 里,它还会把我们救命的"边界"给挤来挤去。有时候你以为自己把两件事打包在同一个事务里,结果还没写完就崩了,数据就开始分崩离析。于是我把自己踩过的坑整理成这篇小记,愿意当你们的"救火绳"。

在一个典型的微服务场景里,往往会有一组相关的操作需要原子性:下单、扣库存、扣钱、发消息。这些步骤如果放在不同的事务里,哪怕只有一个环节失败,整条链路就会不一致。最常见的坑,是把库存扣减放在一个"独立事务"里(比如 Propagation.REQUIRES_NEW),而把下单和支付放在外层同一个事务里。结果就是:下单回滚了,库存却已经提交了,账也可能不一致。嗯,这就是传说中的"数据对不上号"的大坑。

踩坑瞬间

  • 场景要点:父事务包含多个子调用,子调用中有一个用到了 REQUIRES_NEW 的独立事务。父事务抛出异常后,子事务已经提交,导致最终数据不一致。

  • 关键代码节选(简化版,聚焦点在传播行为):

java 复制代码
@Service
public class OrderService {
  @Autowired private InventoryService inventoryService;
  @Autowired private PaymentService paymentService;

  @Transactional
  public void placeOrder(OrderDTO o) {
     inventoryService.reserve(o.getItemId(), o.getQty()); // 子调用在独立事务中执行
     paymentService.charge(o.getAmount()); // 仍在父事务内
     // ... 业务逻辑
     if (someError) throw new RuntimeException(); // 回滚父事务
  }
}

@Service
public class InventoryService {
  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void reserve(Long itemId, int qty) {
     // 扣减库存,然后提交独立事务
  }
}

这段看起来像是"让两段逻辑都走完"的设计,实际效果却是:如果某处后续异常导致父事务回滚,库存的扣减已经在自己的独立事务里提交,永远不会被回滚。数据就成了两份不一致的账。

经验启示

  • 了解回滚边界:传播行为不是"好用就行",它其实在告诉你哪部分应该随父事务一起回滚,哪部分可以独立提交。明确哪些操作必须原子性地一起成功/失败。

  • 避免对相关业务使用 REQUIRES_NEW:如果你的下单、库存、支付是一个完整的业务流程,尽量让它们在同一个事务内完成,避免中间出现独立提交导致的最终不一致。

  • 需要独立提交时,也要有补偿机制:把"独立事务"放在真正独立的业务边界,如异步消息、外部系统调用后再做补偿,而不是直接让它们嵌在同一个调用链里随父事务的生死起伏。

  • 配置回滚规则要清晰:默认情况下运行时会回滚 RuntimeException,但如果你有自定义的异常类型,记得通过 rollbackFor 指定哪些异常会触发回滚,以免误判。

  • 小结:在设计事务边界时,先画好"数据一致性 needs"图,再决定传播行为。否则你写再多注解,也难免遇到那种在开发时"看起来对"的方案,上线就变成"大坑"。

写在最后

如果你现在还在犹豫传播行为到底怎么选,给自己一个简单的口径:要对数据强一致的部分,用同一个事务把相关调用绑死;要对外部系统或长时间任务进行解耦,使用明确的独立边界并配好补偿逻辑。别让一个小小的传播选择,把后续几十行代码的正确性全都打碎。愿你我都能在复杂的分布式场景里,靠这点"边界感"活成稳稳的老程序员。

相关推荐
Ysx4 分钟前
比"本地全绿"更可怕的坑:"交付了"不等于"生效了"
java·后端
武子康5 分钟前
ESP32-S3 分核后仍报 AFE 缓冲区满?先查输入合同
人工智能·后端·agent
Zheone7 分钟前
《Java开发者视角:利用AI辅助审计Spring Boot接口越权漏洞的初步实践》
后端
god_cvz8 分钟前
第三章:4、补充:对话记忆与会话管理
后端·ai编程
弈栈录10 分钟前
用户、会话与消息表应该如何设计
数据库·后端
maozhenzhong11 分钟前
接口加解密与安全通信方案
后端
god_cvz13 分钟前
第三章:5、MCP协议入门
后端·ai编程
RaaS10015 分钟前
AI网关选型指南:MAI Gateway(魔芋企业级AI网关)vs 开源方案全面对比
前端·后端
明月_清风22 分钟前
ClickHouse 实战指南:为什么它能做到"亿级数据秒级查询"?
后端·数据分析
Wx-bishekaifayuan33 分钟前
springboot铜仁非遗之家76938-计算机课程设计、毕业设计
java·spring boot·后端·spring·django·课程设计·旅游