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

Spring Boot中@Transactional注解抛出异常时未回滚JPA保存操作问题排查

问题分析与解决方案

看起来你遇到的核心问题是事务边界设置错误,导致数据库操作提前提交,后续抛出异常时无法触发回滚。我来帮你一步步排查和解决:

问题根源

你的finishWalletTransaction方法上标注了@Transactional,这意味着这个方法执行时会开启一个独立事务。当该方法执行完毕(数据库保存操作完成),这个事务就会自动提交。后续在doWalletOperation中抛出的异常,已经和之前提交的事务无关,自然无法回滚已经写入数据库的记录。

另外补充一点:doWalletOperation是private方法,即使你给它加@Transactional也不会生效——Spring AOP代理只能拦截public方法的调用。

具体解决方案

1. 调整事务边界到业务入口

把事务注解移到整个业务流程的入口方法(也就是doWalletOperation所在的类),确保整个操作处于同一个事务中:

@Service
public class YourBusinessService { // 假设这是doWalletOperation所在的业务类
    @Autowired
    private CommonTransactionalService commonTransactionalService;
    // 其他依赖注入...

    // 把事务注解加到public的业务入口方法上
    @Transactional(rollbackFor = {RuntimeException.class, WalletException.class})
    public BtoBWalletTransactionResponseModel doWalletOperation(BtoBWalletTransactionTypes transactionType, BtoBWalletTransactionRequestModel transactionRequest) {
        try {
            // 省略获取userWallet、btoBWalletTransaction等前置逻辑
            BtoBWalletTransaction savedTransaction = commonTransactionalService.finishWalletTransaction(userWallet, btoBWalletTransaction);
            log.info("wallet {} txn of amount {} for user {}",transactionType.name(),txnAmount,userId);
            // 抛出异常以触发回滚
            throw new RuntimeException("Time to Rollback");
        } catch(Exception e){
            log.error(e.getMessage());
            log.error("error while doing wallet operations for user {}",userId);
            throw new WalletException(e.getMessage());
        }
    }
}

2. 移除下层方法的事务注解

因为现在事务由上层业务入口统一管理,所以需要删除CommonTransactionalServiceImpl中finishWalletTransaction方法上的@Transactional:

@Service
public class CommonTransactionalServiceImpl implements CommonTransactionalService {
    @Autowired
    private BtoBWalletTransactionRepo btoBWalletTransactionRepo;
    @Autowired
    private BtoBUserWalletRepo btoBUserWalletRepo; // 补充你代码中遗漏的注入

    @Override
    public BtoBWalletTransaction finishWalletTransaction(BtoBUserWallet userWallet, BtoBWalletTransaction walletTransaction) {
        BtoBWalletTransaction savedTransaction = btoBWalletTransactionRepo.save(walletTransaction);
        btoBUserWalletRepo.save(userWallet);
        return savedTransaction;
    }
}

3. 确认异常回滚配置

注意:如果你的WalletException是自定义的checked异常(继承自Exception而非RuntimeException),默认@Transactional不会对其触发回滚,所以需要在注解中显式指定回滚的异常类型,就像上面代码中写的rollbackFor = {RuntimeException.class, WalletException.class}。

4. 验证Spring事务基础配置

确保你的Spring Boot应用已经正确开启事务管理:

  • 启动类可以添加@EnableTransactionManagement注解(Spring Boot默认会自动配置,但显式添加更稳妥)
  • 所有涉及事务的类都是通过@Autowired注入的Spring Bean,而非手动new的对象(手动实例化的对象不会被Spring代理,事务注解无效)

测试验证

调整完成后,重新运行代码:当doWalletOperation抛出RuntimeException时,整个事务会被回滚,finishWalletTransaction中的两次数据库保存操作都会被撤销。

内容的提问来源于stack exchange,提问作者Himanshu Ranjan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 17:22:40