Spring 事务失效解决

7 篇文章 0 订阅
2 篇文章 0 订阅

准确描述: 同一个对象内的嵌套方法调用 Spring AOP拦截失效

原理参考:《Spring 揭秘》 12.1 有关公开当前调用的代理对象的探讨
《Spring 揭秘》12.1 读书笔记

问题代码示例

public interface AService {  
    public void a();  
    public void b();  
}  
   
@Service  
public class AServiceImpl implements AService{  
    @Transactional(propagation = Propagation.REQUIRED)  
    public void a() {  
        this.b();  
    }  
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)  
    public void b() {  
    }  
}

观察现象

直接现象

b方法事务注解失效

调试现象

使用如下 Step Into 按钮,来调试。
image.png

@PostMapping("/a")
public void test() {
    aService.a();
}

可以看到,我们调用a方法的调用栈,是进入了CglibAopProxy当中。这个事务是生效的
image.png

再看看b方法的调用:直接进入到了实际方法,而没有经过CglibAopProxy

image.png

透过现象看本质

b方法中的 this 指向目标对象,并非代理对象。因此调用 this.b() 将不会执行b方法的事务切面,即不会执行事务增强,因此b方法的事务定义@Transactional(propagation = Propagation.REQUIRES_NEW)将不会实施.

解决方案

  1. 使用 expose-proxy 属性来暴露代理对象后,使用以下代码调用,这样在调试后,便进入了CglibAopProxy当中。(这种方案需要开启AspectJ)
AService aService = (AService) AopContext.currentProxy();
aService.b();

方案原理

参考 CglibAopProxy#intercept 方法

if (this.advised.exposeProxy) {
    // Make invocation available if necessary.
    oldProxy = AopContext.setCurrentProxy(proxy);
    setProxyContext = true;
}

finally {
    // ...
    if (setProxyContext) {
        // Restore old proxy.
        AopContext.setCurrentProxy(oldProxy);
    }
}
  1. 在实际项目中,大多情况下建议在 controller 直接调用的service 方法,(在本示例中为a方法)开启一个完整的物理事务,并在调用的子方法上,也标注事务(如本示例中的b方法)。

参考资料:

@Transactional - spring.io

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值