Spring Boot 事务注解失效?我花了一个下午才找到原因

前两天写一个下单逻辑,代码逻辑没问题,单元测试也过了,但一联调就发现——事务压根没生效

数据该插的插进去了,该回滚的时候也没回滚。

问题重现

java

@Service
public class OrderService {
    @Transactional
    public void createOrder(OrderDTO dto) {
        // 保存订单
        orderDao.insert(order);
        // 扣减库存 —— 这里抛异常了
        inventoryService.decrease(dto.getProductId(), dto.getCount());
    }
}

简单来说就是:createOrder 方法抛了异常,但前面的订单数据没有回滚

排查过程

排查了两个方向:

  1. 数据库引擎是 InnoDB 吗? 是的,支持事务。

  2. Spring 事务配置有问题? 默认配置,没改动。

最后发现,问题出在 @Transactional 默认只回滚 RuntimeException,而我抛的是一个自定义的 BusinessException,它继承的是 Exception,不是 RuntimeException

解决方案

改成这样就行了:

java

@Transactional(rollbackFor = Exception.class)
public void createOrder(OrderDTO dto) {
    // ...
}

加上 rollbackFor = Exception.class,告诉 Spring:“只要抛异常,不管是什么类型,都给我回滚。”

一个小提醒

如果你的 Service 方法被同一个类里的另一个方法调用,@Transactional 也可能失效。因为 Spring 事务是通过代理实现的,内部调用走的是 this,不是代理对象。

解决方法也不复杂:把事务方法抽到单独的 Service 里,或者用 AopContext.currentProxy() 拿到代理对象。