在同一个类直接调用事务方法,就会导致事务不生效

2,851 阅读2分钟

[转载自](spring同类调用事务不生效-原因及三种解决方式 - 简书 (jianshu.com))

(Spring事务失效的 8 大原因,这次可以吊打面试官了! - 知乎 (zhihu.com))

在同一个类直接调用事务方法,就会导致事务不生效

来看两个示例:

@Service
public class OrderServiceImpl implements OrderService {

    public void update(Order order) {
        updateOrder(order);
    }

    @Transactional
    public void updateOrder(Order order) {
        // update order
    }

}

update方法上面没有加 @Transactional 注解,调用有 @Transactional 注解的 updateOrder 方法,updateOrder 方法上的事务管用吗?

再来看下面这个例子:

@Service
public class OrderServiceImpl implements OrderService {

    @Transactional
    public void update(Order order) {
        updateOrder(order);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateOrder(Order order) {
        // update order
    }

}

这次在 update 方法上加了 @Transactional,updateOrder 加了 REQUIRES_NEW 新开启一个事务,那么新开的事务管用么?

这两个例子的答案是:不管用!

因为它们发生了自身调用,就调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效,这也是老生常谈的经典问题了。

这个的解决方案之一就是在的类中注入自己,用注入的对象再调用另外一个方法,这个不太优雅,另外一个可行的方案可以参考《Spring 如何在一个事务中开启另一个事务?》这篇文章。

原因:

事务不生效的原因在于,spring基于AOP机制实现事务的管理,@Authwired StudentService studentService这样的方式,调用StudentService的方法时,实际上是通过StudentService的代理类调用StudentService的方法,代理类在执行目标方法前后,加上了事务管理的代码。\

image.png

因此,只有通过注入的StudentService调用事务方法,才会走代理类,才会执行事务管理;如果在同类直接调用,没走代理类,事务就无效。
注意:除了@Transactional,@Async同样需要代理类调用,异步才会生效