news 2026/5/4 18:34:02

别再死记硬背了!用转账、发红包、查余额三个场景,彻底搞懂Spring事务传播机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再死记硬背了!用转账、发红包、查余额三个场景,彻底搞懂Spring事务传播机制

从转账失败到红包纠纷:用真实案例拆解Spring事务传播机制

银行转账时对方没收到钱却扣了款?微信群红包抢到后系统崩溃导致金额消失?这些看似简单的场景背后,都藏着事务传播机制的玄机。今天我们不谈晦涩的定义,就用三个你每天都会遇到的业务场景,把Spring事务的七种传播行为变成可感知的代码逻辑。

1. 银行转账:理解REQUIRED与REQUIRES_NEW的本质区别

上周同事小李遇到个诡异问题:用户A向B转账100元,B的余额增加了,A的余额却没减少。查看代码发现,转账服务调用了两个DAO方法:

@Transactional public void transfer(String from, String to, double amount) { accountDao.addBalance(to, amount); // 先加钱 accountDao.deductBalance(from, amount); // 后扣款 }

当第二个DAO操作抛出数据库连接异常时,理论上整个转账应该回滚。但实际B的余额变化被提交了——这就是REQUIRED传播行为的典型陷阱。在默认配置下,两个DAO方法共享同一个事务,但某些数据库驱动在连接异常时可能无法正常回滚。

对比下面这个红包场景:

@Transactional(propagation = Propagation.REQUIRES_NEW) public void sendRedPacket(User sender, double amount) { walletDao.deduct(sender, amount); redPacketDao.create(sender, amount); // 独立事务记录红包 }

即使后续的红包领取操作失败,红包创建记录也会持久化。这就是REQUIRES_NEW的价值——关键操作需要独立事务保障,就像快递丢了货物,但物流信息必须保留。

传播行为事务关系异常影响范围适用场景
REQUIRED加入当前/新建事务整个事务链回滚普通转账、订单创建
REQUIRES_NEW新建独立事务仅当前操作回滚日志记录、凭证生成

关键认知:REQUIRED像团队项目——一人犯错全组担责;REQUIRES_NEW像外包合作——甲方乙方互不影响

2. 微信红包背后的嵌套事务:NESTED的精妙设计

春节抢红包时遇到这种情况吗?点击"开"之后界面卡住,重新进入发现红包没了,余额也没增加。这引出了NESTED传播行为的特殊价值:

@Transactional public void openRedPacket(User user, String packetId) { // 主事务:红包状态更新 redPacketDao.markAsOpened(packetId); // 嵌套事务:余额增加 walletService.addBalanceNested(user, getAmount(packetId)); } @Transactional(propagation = Propagation.NESTED) public void addBalanceNested(User user, double amount) { walletDao.add(user, amount); // 模拟网络异常 if(new Random().nextBoolean()) throw new RuntimeException(); }

NESTED的独特之处在于:

  • 子事务回滚不影响父事务(红包状态仍会变为"已开启")
  • 父事务回滚必然导致子事务回滚(主事务失败会撤销余额变更)
  • 数据库必须支持保存点(Savepoint)机制

这种"部分回滚"特性特别适合:

  • 红包领取、优惠券核销等可分步操作
  • 需要保留操作痕迹的业务场景
  • 非核心流程与主流程解耦

3. 余额查询的轻量级策略:SUPPORTS与NOT_SUPPORTED的平衡术

高频访问的余额查询该用哪种传播行为?对比两种实现:

// 方案A:默认REQUIRED @Transactional public double getBalance(String account) { return accountDao.query(account); } // 方案B:SUPPORTS优化 @Transactional(propagation = Propagation.SUPPORTS) public double getBalance(String account) { return accountDao.query(account); }

当查询方法被其他事务方法调用时:

  • REQUIRED会强制加入现有事务,可能引发不必要的锁竞争
  • SUPPORTS智能适配当前事务状态,无事务时自动降级

但有些场景需要更极致的优化:

@Transactional(propagation = Propagation.NOT_SUPPORTED) public List<Transaction> queryHistory(String account) { // 大数据量查询,明确不要事务 return historyDao.queryLargeDataSet(account); }

三种非强制事务策略对比:

  1. SUPPORTS

    • 有事务则用,没有不强求
    • 典型应用:余额查询、商品详情
  2. NOT_SUPPORTED

    • 强制非事务执行,挂起现有事务
    • 典型应用:数据导出、统计报表
  3. NEVER

    • 严格禁止事务上下文
    • 典型应用:缓存预热、健康检查

4. 组合拳实战:电商下单中的传播行为设计

看一个完整的订单创建流程如何合理运用传播机制:

@Transactional public Order createOrder(OrderDTO dto) { // REQUIRED(默认):核心业务必须事务 inventoryService.deductStock(dto.getItems()); // REQUIRES_NEW:日志记录独立保存 auditLogService.logOperation("CREATE_ORDER", dto.getUser()); // NESTED:优惠计算可部分回滚 couponService.applyCoupons(dto); // NOT_SUPPORTED:风控检查不要事务 riskControlService.check(dto); return orderDao.save(dto); }

各服务方法配置示例:

// 库存服务 @Transactional(propagation = Propagation.MANDATORY) public void deductStock(List<Item> items) { // 必须在外层事务中执行 } // 审计日志 @Transactional(propagation = Propagation.REQUIRES_NEW) public void logOperation(String action, User user) { // 独立事务记录 } // 优惠券服务 @Transactional(propagation = Propagation.NESTED) public void applyCoupons(OrderDTO dto) { // 可独立回滚的计算 }

这种组合策略实现了:

  • 核心数据强一致性(库存、订单)
  • 辅助功能可靠性(日志)
  • 非关键操作灵活性(风控)
  • 复杂业务可维护性(优惠计算)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 18:28:27

观察Taotoken在多模型聚合调用下的延迟表现与路由稳定性

观察Taotoken在多模型聚合调用下的延迟表现与路由稳定性 1. 多模型调用的延迟表现 在实际开发过程中&#xff0c;我们通过Taotoken的统一API接口调用了包括Claude、GPT等在内的多个主流模型。从开发者体验来看&#xff0c;平台提供的HTTP接口响应速度保持在合理范围内&#x…

作者头像 李华
网站建设 2026/5/4 18:23:59

基于Next.js的全栈CRM系统架构设计与工程实践

1. 项目概述与核心价值最近在开源社区里&#xff0c;我注意到一个名为pdovhomilja/nextcrm-app的项目&#xff0c;它迅速引起了我的兴趣。作为一名长期在客户关系管理&#xff08;CRM&#xff09;和企业应用开发领域摸爬滚打的从业者&#xff0c;我深知一个现代化、可扩展且易于…

作者头像 李华
网站建设 2026/5/4 18:23:07

避开OpenCV新手坑:minMaxLoc函数处理多通道图像和空矩阵的5个常见错误

避开OpenCV新手坑&#xff1a;minMaxLoc函数处理多通道图像和空矩阵的5个常见错误 在图像处理领域&#xff0c;minMaxLoc函数是OpenCV工具箱中最基础却又最容易被误用的函数之一。许多开发者在使用这个看似简单的极值查找工具时&#xff0c;往往忽略了它对输入数据的严格要求&a…

作者头像 李华
网站建设 2026/5/4 18:20:25

别再死记硬背了!用‘蛋糕店’的故事5分钟搞懂K8s Operator和Informer

蛋糕店经营秘籍&#xff1a;用商业逻辑秒懂Kubernetes Operator 想象你正经营一家高端定制蛋糕店&#xff0c;每天要处理上百份特殊订单。顾客们不仅要求不同口味的蛋糕&#xff0c;还需要个性化装饰、特殊包装和定时配送。作为店主&#xff0c;你需要一套高效的系统来管理这些…

作者头像 李华