Spring中同一类@Transactional修饰方法相互调用的坑

it2025-05-02  22

1.问题1的提出

class AServiceImpl{ @AutoWide BService bService; @Transactional public void a() { bService.b(); bService.c(); int i =10/0; } } class BServiceImpl{ @Transactional(propagation = Propagation.REQUIRED,timeout = 2) public void b() { } @Transactional(propagation = Propagation.REQUIRES_NEW,timeout = 2) public void c() { } }

bService.b()方法使用默认的传播行为REQUIRED,和a共用一个事务, int i =10/0;出现异常需要回滚,b会回滚。 bService.c()方法使用默认的传播行为REQUIRES_NEW,和a不共用一个事务, int i =10/0;出现异常需要回滚,b会回滚。

结论:bService.b()回滚,bService.c()不回滚。

2.问题2的题提出

class AServiceImpl{ @Transactional @Transactional public void a() { b(); c(); } @Transactional(propagation = Propagation.REQUIRED,timeout = 2) public void b() { System.out.println("b"); } @Transactional(propagation = Propagation.REQUIRES_NEW,timeout = 2) public void c() { System.out.println("c"); } }

的写法和下面的写法一模一样:

class AServiceImpl{ @Transactional public void a() { System.out.println("b"); System.out.println("c"); } }

即b和c自己的事务失效,完全相当于拷贝代码到a方法中。如果我们想要的是各自拥有自己的自治的事务,该怎么办呢?为什么会出现这个问题?

2.1为什么为出现bc方法事务失效的问题?

原因:@Transactional 底层使用的是aop,使用的代理对象才能使用事务,本方法内部嗲用,绕过了代理对象,所以bc事务无效,a仍然有效(如果其类通过代理对象调用的话)。

2.2解决方案

1.先引入aspactj的依赖:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 在嗲用b,c方法之前通过切面重新获得此对象的代理AServiceImpl aService = AopContext.currentProxy(); 可以解决这个问题。 代码如下: class AServiceImpl{ @Transactional public void a() { AServiceImpl aService = AopContext.currentProxy(); aService.b(); aService.c(); } @Transactional(propagation = Propagation.REQUIRED,timeout = 2) public void b() { System.out.println("b"); } @Transactional(propagation = Propagation.REQUIRES_NEW,timeout = 2) public void c() { System.out.println("c"); } }

2.3其他的解决方案

另外在抽象出一层,做事务层,不要把相互调用的方法放到一类中

2.4错误的解决方案

这种会造成循环依赖,会爆炸:

@AutoWide AServiceImpl AServiceImpl; 前路无畏 认证博客专家 专家认证 自律的艰辛总甜过懊悔的苦果!专注于java后端技术及解决方案,善于总结,分享!自律的艰辛总甜过懊悔的苦果!专注于java后端技术及解决方案,善于总结,分享!自律的艰辛总甜过懊悔的苦果!专注于java后端技术及解决方案,善于总结,分享!
最新回复(0)