Spring Boot @Transactional事务未回滚问题求助
嘿,这问题我碰到过好多次——明明加了@Transactional,抛了异常却留着第一个实体,太闹心了!我帮你梳理几个最可能的原因,一步步排查:
1. 最常见的坑:异常被悄悄吞掉了
如果你的cadastraProduto方法里,调用第二个实体保存(比如importSkuService的方法)时用了try-catch,但只打了日志没重新抛出异常,Spring的事务拦截器根本感知不到异常,当然不会触发回滚!
比如这种错误写法:
try { importSkuService.save(sku); // 这里抛出DuplicateEntityException } catch (DuplicateEntityException e) { log.error("SKU重复了", e); // 没重新抛出,事务就认为一切正常 }
修复:要么删掉try-catch让异常直接往上抛,要么在catch块里重新抛出:throw e;(或者包装成RuntimeException,比如throw new RuntimeException("保存SKU失败", e);)。
2. 事务注解根本没生效
Spring事务是靠动态代理实现的,这几个情况会导致注解失效:
- 内部方法调用:如果是同一个类里的非事务方法调用了这个带
@Transactional的cadastraProduto方法,代理不会生效,事务等于白加。 - 方法不是public:Spring事务注解只对public方法生效,private/protected方法上的注解会被直接忽略。
3. 事务管理器配置有问题
如果你的项目有多数据源,要确认@Transactional指定了正确的事务管理器,比如:
@Transactional(transactionManager = "produtoTxManager", rollbackFor = {DuplicateEntityException.class, Exception.class})
另外,检查DuplicateEntityException是不是Checked Exception?不过你已经把它加到rollbackFor里了,这条重点看多数据源场景。
4. 保存操作没加入当前事务
确保importProdutoRepository是Spring Data JPA的接口(或者被Spring正确托管),如果是自己手写的JDBC操作,有没有手动获取事务连接?要是绕开了Spring的事务管理,保存操作就不会受@Transactional控制。
快速验证小妙招
在cadastraProduto方法开头加一行代码,看看事务到底开没开:
System.out.println("当前是否有活跃事务:" + TransactionSynchronizationManager.isActualTransactionActive());
如果输出false,那肯定是事务没生效,回到前面的代理问题排查。
内容的提问来源于stack exchange,提问作者Guilherme Melo

