Sping 同一个类中的方法调用,事物不生效

前言:有时候在编写代码过程中,遇到事物不生效的问题,特此总结一下
代码如下
public class DemoTransactional {

    public void demoTestA() {
        // sql执行逻辑 。。。
        demoTestB();
    }
    @Transactional
    public void demoTestB() {
        // sql执行逻辑 。。。
    }
}

测试结果如下:

  • 经过测试发现,当demoTestA方法调用同类中带有@Transactional注解的demoTestB方法时,被@Transactional注解的demoTestB方法的事务是不起作用的
原因如下:

Spring采用动态代理(AOP)实现对bean的管理和切片,它为我们的每个class生成一个代理对象。只有在代理对象之间进行调用时,可以触发切面逻辑。
而在同一个class中,demoTestA调用方法demoTestB,调用的是原对象的方法,而不通过代理对象。所以Spring无法切到这次调用,也就无法通过注解保证事务性了。
也就是说,在同一个类中的方法调用,则不会被方法拦截器拦截到,因此事务不会起作用。

另一种理解

Spring在处理@Tranasctional注解时,会“proxy”当前的类。如果A和B两个类都有@Transactional时,实际上运行的是A的代理类A‘, A,B的代理类B', B四个类的instance。一个外部服务调用A,实际上是 外部-->A'-->A-->B'-->B这样执行的。而抛出异常的代码实际上是在B‘做的。但是如果是同一个类内部方法直接调用的话,那么就是简单的方法直接调用,即 外部-->A'-->A方法1-->A方法2。 A方法1不会找到A'去调用。于是,“传播”的规则不会生效。

解决方法
  • 将带有@Transactional注解的方法移到另一个类中,发起类之间的方法调用。
  • 在第一个方法中也添加@Transactional注解。
    经过测试的情况总结
    前提:demoTestA方法调用demoTestB方法时,demoTestB方法有多个修改SQL
测试结果
  • demoTestA方法没开启事务,demoTestB方法开启事务:demoTestAdemoTestB在同一类中,事务无效;demoTestAdemoTestB不在同一类中,事务生效。
  • demoTestA方法开启事务,demoTestB方法没开启事务:demoTestAdemoTestB在同一类中,事务生效;demoTestAdemoTestB不在同一类中,事务生效。

你可能感兴趣的:(Sping 同一个类中的方法调用,事物不生效)