从@Transactional,@Async 失效说起

2020/03/12 17:44 下午 posted in  数据库

1、问题描述

当我们在同一个类中,调用一个被@Transactional,或@Async标注的方法时,这些注解是否会生效?

结论是不会。

2、原因

Spring采用动态代理(AOP)实现对bean的管理和切片,它为我们的每个class生成一个代理对象。只有在代理对象之间进行调用时,可以触发切面逻辑。

spring 在扫描bean的时候会扫描方法上是否包含@Async注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用时增加异步作用。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就没有增加异步作用,我们看到的现象就是@Async注解无效。

当我们调用A的bean的a()方法的时候,也是被proxyA拦截,执行proxyA拦截,执行proxyA.a()(标记3),然而,由以上代码可知,这时候它调用的是objectA.a(),也就是由原来的bean来调用a()方法了,所以代码跑到了“标记1”。由此可见,“标记2”并没有被执行到,所以异步执行的效果也没有运行。

特别注意: 当Spring的事务在同一个类时,它的自我调用时事务将失效.
@Async

解决方案

方案一

在当前类中通过上下文获取自己的代理对象调用异步方法

直接@Autowired

方案二

基于 AopContext 暴露代理对象

EnableAspectJAutoProxy(exposeProxy=true)
AopContext.currentProxy()

https://mp.weixin.qq.com/s/m7p7AP_zT1JEZrxwmVISVQ

方案三

从外部类调用