阿昌教你解决在SpringBoot同一个对象内,事务方法互调默认失效问题
阿昌 Java小菜鸡
## 前言

在Springboot中如果一个AService中a/b/c 方法,那么 b、c 做的传播行为配置,都不会起作用,也就是说b、c都会跟 a 共用一个事务都采用@Transactional(propagation = Propagation.REQUIRED),这个注解就会失效;

除非b、c在其他不同的 service,那样才能使它们自己的配置生效

image

  • 原因

那为什么会出现这种情况呢?

事务是用代理对象来控制的,如果在 a 里面调用的是同一个 service 的 b、c方法,相当于把 b、c 的代码复制、粘贴过来了,直接调用的本类的方法,而不是通过AOP代理增强调用,也就是跳过了代理


解决

使用代理对象调用b、c方法,即可解决

  • 引入依赖

这里直接使用springboot的jdk默认的动态代理无法实现,我们需要引入AspectJ

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 启动类开启 aspectj 动态代理功能

以后所有的动态代理都是aspectj创建的(即使没有接口也可以创建动态代理),对外暴露代理对象

1
@EnableAspectJAutoProxy(exposeProxy=true)
  • 用代理对象对本类互调

通过AopContext.currentProxy()获取代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Transactional(timeout = 30)
public void a(){
// 直接强转,然后b、c的传播行为设置就能起作用了
OrderServiceImpl orderService = (OrderServiceImpl) AopContext.currentProxy();
orderService.b();
orderService.c();
}

// REQUIRED:单纯的需要一个事务,如果 a 已经有了,就会直接使用 a 的
@Transactional(propagation = Propagation.REQUIRED)
public void b(){}

// REQUIRES_NEW:总是需要一个新的事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void c(){}

这样子就可以解决在Springboot中同一个对象内,事务方法互调默认失效的问题

 请作者喝咖啡