You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中多表保存抛异常时如何实现全链路事务回滚

多表级联保存事务回滚实现方案

核心实现依赖Spring声明式事务,保证三张表的写入操作落在同一个数据库事务中,任意步骤报错时所有已执行写入全部回滚,具体操作如下:

  • 在业务方法上添加@Transactional注解,配置rollbackFor = Exception.class,覆盖所有异常类型的回滚触发场景。默认配置下Spring事务仅对RuntimeException、Error类型异常触发回滚,自定义异常、SQL异常等受检异常如果不配置该参数会出现不回滚的问题。
  • 规避事务失效的常见场景:
    1. @Transactional注解仅对public方法生效,非public方法加注解不会触发事务
    2. 禁止在方法内部直接catch所有异常不向外抛出,Spring感知不到异常发生就不会触发回滚,如果有特殊逻辑需要捕获异常处理,处理完成后必须重新抛出异常
    3. 禁止同类内部方法直接调用加了事务注解的方法,会绕过Spring AOP代理导致事务失效
    4. 多数据源场景下需要明确指定注解的transactionManager属性,匹配三张表所属数据源对应的事务管理器
  • 改造后的代码参考:
@Override
@Transactional(rollbackFor = Exception.class)
public ApiResponse saveVoucher(APVoucherBatch batch) {
    APVoucherBatch savedBatch = voucherBatchRepo.save(batch);  // 主表写入
    // 写入分录表
    List<APVoucherEntry> entryList = batch.getEntryList();
    for(APVoucherEntry info: entryList){
        info.setVoucherBatch(savedBatch);
        info.setBatchNo(savedBatch.getBatchNo());
        APVoucherEntry savedEntry = entryRepo.save(info);   // 子表1写入

        // 写入凭证明细表
        List<APVoucherEntryDetails> detailsList = info.getDetailsList();
        for(APVoucherEntryDetails dtl: detailsList){
            dtl.setBatchList(savedBatch);
            dtl.setEntryInfo(savedEntry);
            detailsRepo.save(dtl);     // 子表2写入,任意报错都会触发全链路回滚
        }
    }
    return new ApiResponse();
}
  • 配置完成后可以做异常触发验证:手动给明细表的字段设置不符合数据库约束的值(比如超长字符串、非空字段设null)触发保存报错,查询数据库确认主表、分录表没有残留插入数据,即代表事务回滚逻辑生效。

内容的提问来源于stack exchange,提问作者Arif Hosain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:06:26