从转账失败到红包纠纷用真实案例拆解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); } // 方案BSUPPORTS优化 Transactional(propagation Propagation.SUPPORTS) public double getBalance(String account) { return accountDao.query(account); }当查询方法被其他事务方法调用时REQUIRED会强制加入现有事务可能引发不必要的锁竞争SUPPORTS智能适配当前事务状态无事务时自动降级但有些场景需要更极致的优化Transactional(propagation Propagation.NOT_SUPPORTED) public ListTransaction queryHistory(String account) { // 大数据量查询明确不要事务 return historyDao.queryLargeDataSet(account); }三种非强制事务策略对比SUPPORTS有事务则用没有不强求典型应用余额查询、商品详情NOT_SUPPORTED强制非事务执行挂起现有事务典型应用数据导出、统计报表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(ListItem items) { // 必须在外层事务中执行 } // 审计日志 Transactional(propagation Propagation.REQUIRES_NEW) public void logOperation(String action, User user) { // 独立事务记录 } // 优惠券服务 Transactional(propagation Propagation.NESTED) public void applyCoupons(OrderDTO dto) { // 可独立回滚的计算 }这种组合策略实现了核心数据强一致性库存、订单辅助功能可靠性日志非关键操作灵活性风控复杂业务可维护性优惠计算