Spring中多表保存抛异常时如何实现全链路事务回滚
多表级联保存事务回滚实现方案
核心实现依赖Spring声明式事务,保证三张表的写入操作落在同一个数据库事务中,任意步骤报错时所有已执行写入全部回滚,具体操作如下:
- 在业务方法上添加
@Transactional注解,配置rollbackFor = Exception.class,覆盖所有异常类型的回滚触发场景。默认配置下Spring事务仅对RuntimeException、Error类型异常触发回滚,自定义异常、SQL异常等受检异常如果不配置该参数会出现不回滚的问题。 - 规避事务失效的常见场景:
@Transactional注解仅对public方法生效,非public方法加注解不会触发事务- 禁止在方法内部直接catch所有异常不向外抛出,Spring感知不到异常发生就不会触发回滚,如果有特殊逻辑需要捕获异常处理,处理完成后必须重新抛出异常
- 禁止同类内部方法直接调用加了事务注解的方法,会绕过Spring AOP代理导致事务失效
- 多数据源场景下需要明确指定注解的
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
相关产品推荐
相关产品推荐

