1、异常捕获处理,自己处理了异常,没有抛出
Spring 事务回滚是由TransactionInterceptor在捕获到业务方法向外抛出的异常后触发的。如果在业务里try-catch把异常吃掉了、没有重新抛出,拦截器就感知不到异常,会走 commit 分支导致事务失效。
以下是由于异常捕获处理导致的事务失效的场景与修复
try-catch 完全吞掉异常
try { doSomething(); } catch (Exception e) { log.error("转账失败", e); } // 拦截器看不到异常 → 提交应该修复为:
@Transactional public void transfer(...) { try { doSomething(); } catch (Exception e) { log.error("转账失败", e); throw new BizException("转账失败", e); // 必须抛 } }2、抛出检查异常
默认只回滚 RuntimeException(运行时异常,非受检异常),受检异常需要配置rollbackFor = Exception.class。
受检查异常默认不回滚
@Transactional // 默认只回滚 RuntimeException / Error public void doSomething() throws IOException { throw new IOException("IO错误"); // 受检异常,默认不回滚! }应该修复为:
@Transactional(rollbackFor = Exception.class) // 显式指定 public void doSomething() throws IOException { throw new IOException("IO错误"); }3、非 public 方法导致的事务失效
@Transactional只对public方法生效。如果标注在private、protected或包级(default)方法上,Spring 会静默忽略该注解——不报错,但方法完全没有事务能力。
失效案例:调用createOrder时:数据照插,异常照抛,但事务从未开启。
@Service public class OrderService { @Autowired private OrderMapper orderMapper; @Transactional private void createOrder(Order order) { // ❌ private → 事务不生效 orderMapper.insert(order); // 抛异常也不会回滚 throw new RuntimeException("测试"); } }解决方案:直接把方法改为 public
@Transactional public void createOrder(Order order) { orderMapper.insert(order); }