文章目录
- 前言
- this调用是什么
- this调用事务失效案例
- this调用事务仍然生效案例?
- 总结
- 如何解决this调用事务失效
前言
我们经常谈到Spring事务失效会有多种场景导致:可参考我另外一篇文章 一文清晰讲解@Transactional 注解失效场景
- @Transactional 应用在非 public 修饰的方法上
- @Transactional 注解属性 propagation 设置错误
- @Transactional 注解属性 rollbackFor 设置错误
- 同一个类中方法调用,导致@Transactional失效
- 异常被你的 catch“吃了”导致@Transactional失效
- 数据库引擎不支持事务
- this自调用
这里上面谈到的this自调用真的一定会导致事务失效吗?这就是本文要探索的内容
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方法有几种情况:
- public void test2()
- private void test2()
- 加上注解
@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()
- 在当前类中注入自己
- 使用手动事务