Spring事务this自调用的理解误区?真的会让事务失效吗?

文章目录

      • 前言
      • this调用是什么
      • this调用事务失效案例
      • this调用事务仍然生效案例?
        • 总结
      • 如何解决this调用事务失效

前言

我们经常谈到Spring事务失效会有多种场景导致:可参考我另外一篇文章 一文清晰讲解@Transactional 注解失效场景

  • @Transactional 应用在非 public 修饰的方法上
  • @Transactional 注解属性 propagation 设置错误
  • @Transactional 注解属性 rollbackFor 设置错误
  • 同一个类中方法调用,导致@Transactional失效
  • 异常被你的 catch“吃了”导致@Transactional失效
  • 数据库引擎不支持事务
  • this自调用

这里上面谈到的this自调用真的一定会导致事务失效吗?这就是本文要探索的内容

Spring事务this自调用的理解误区?真的会让事务失效吗?_第1张图片

this调用是什么

  • 在Java中,关键字"this"表示当前对象的引用。它可以用于引用当前对象的实例变量、调用当前对象的方法或构造函数。
class MyClass {
    public void doSomething() {
        // 执行一些操作
    }

    public void doSomethingElse() {
        this.doSomething(); // 使用"this"调用当前对象的方法
    }
}

this调用事务失效案例

@Service
public class UserService {

    @Autowired
    private MyUserMapper myUserMapper;
    
   
    public void test() {
        User user = new User();
        user.setUsername("setUsername");
        user.setPassword("setPassword");
        myUserMapper.add(user);
        this.test2();
    }
    
    @Transactional(rollbackFor = Throwable.class)
    public void test2() {
        User user = new User();
        user.setUsername("setUsername22");
        user.setPassword("setPassword22");
        myUserMapper.add(user);
        int i=1/0;
        user.setUsername("我是修改的数据哦");
        myUserMapper.update(user);    
    }
}

这种情况就是经典的this自调用导致test2方法的事务失效了!

在Spring框架中,"this"调用通常用于在同一个类的不同方法之间进行方法调用。当一个方法在同一个类中调用另一个方法时,如果使用"this"关键字进行调用,那么该调用将不会经过代理对象,而是直接在当前对象上执行方法。

Spring框架的事务管理是基于代理模式实现的。当一个类被声明为一个事务性Bean时,Spring会使用代理对象来管理该Bean的事务。代理对象会拦截方法调用,并在方法执行前后进行事务管理操作。

然而,当一个方法在同一个类的其他方法中通过"this"关键字进行调用时,调用并不会经过代理对象。这意味着事务管理的切面将无法拦截"this"调用,从而导致事务失效。

this调用事务仍然生效案例?

这里说的仍然生效其实是另外一种理解误区,其实本质来说this自调用始终是会导致事务失效的

还是上面的例子改造一下:主要观察test和test2方法上面的注解,这次我们在test方法加上了 @Transactional(rollbackFor = Throwable.class)开启了事务,然后test2方法有几种情况:

  1. public void test2()
  2. private void test2()
  3. 加上注解
 @Transactional(rollbackFor = Throwable.class,propagation = Propagation.NOT_SUPPORTED)
 public void test2()
@Service
public class UserService {

    @Autowired
    private MyUserMapper myUserMapper;
    
    @Transactional(rollbackFor = Throwable.class)
    public void test() {
        User user = new User();
        user.setUsername("setUsername");
        user.setPassword("setPassword");
        myUserMapper.add(user);
        this.test2();
    }
    
    //第2种
    //private void test2(){...}
    
    //第3种
    //@Transactional(rollbackFor = Throwable.class,propagation = Propagation.NOT_SUPPORTED)
 	//public void test2(){...}
 	
    public void test2() {
        User user = new User();
        user.setUsername("setUsername22");
        user.setPassword("setPassword22");
        myUserMapper.add(user);
        int i=1/0;
        user.setUsername("我是修改的数据哦");
        myUserMapper.update(user);    
    }
}

实际运行会发现,上面test2的第3种情况,里面的事务都会进行回滚!!!难道是搞错了? Spring的this自调用不会导致事务失效?

之前我就是一直这样陷入了误区,以为是这样的,其实真实的原因很简单:

test() 方法使用了 @Transactional(rollbackFor = Throwable.class) 注解,表明该方法应该在一个事务中执行。当通过 this.test2() 调用 test2() 方法时,它将在当前事务的上下文中被调用!!!

在 Spring 中,默认情况下,@Transactional 注解被设置为 Propagation.REQUIRED,这意味着如果当前已经存在一个事务,那么方法将在该事务中执行;如果没有事务,将创建一个新的事务。因此,在 test() 方法中调用 this.test()test() 方法将在同一个事务中执行。

总结
  • 所以并不是Spring自调用不会导致事务失效,而是理解问题!
  • test2前两种情况是方法上面根本就没有@Transactional注解,本身就没有事务这一说法,也就不存在所谓的失效、生效了!
  • 而第3种情况加上@Transactional(rollbackFor = Throwable.class,propagation = Propagation.NOT_SUPPORTED)想要方法不支持事务,但是发现它还是有事务??所以确实是它注解上的事务失效了(它本质是为了不要事务,但是现在有事务了,所以是失效了)!!然后因为事务传播特性导致它加入了test方法的事务,看起来是事务生效了(反着来,这里好好品味一下

如何解决this调用事务失效

  • 采用AopContext.currentProxy().方法B名()来进行调用—注意需要在启动类上加一个注解@EnableAspectJAutoProxy(exposeProxy = true)
  • ApplicationContext.getBean()
  • 在当前类中注入自己
  • 使用手动事务

你可能感兴趣的:(深入学习Spring,SSH/SSM,spring,数据库,sql)