你的八股文该更新了,spring事务不会失效了!

157 阅读2分钟

过时的八股文

”哪些场景会导致spring事务失效?“,这是一道经典java面试题

可你有没有想过 除了背出所有的失效场景,还有什么更好的方式来回答这个问题呢? 比如“我解决了spring的这个问题,我是这么解决的。。。”。

今天就来讲讲我是怎么解决的

先看两个高频失效的场景【通过this调用】+【private方法】。


    public void test_this_private(Object vo) {
        // 其他查询
        do_private(vo );
    }

    @Transactional
    private void do_private(Object vo) {
        System.out.println("数据库操作1,2,3。。。");
    }

为什么高频?我们为了控制事务的粒度,会把数据库修改的操作集合抽象成一个私有方法。 那么此时事务就失效了,解决办法一般有两个。

一,把私有改成public,然后获取代理对象,再通过代理对象进行调用

二,把方法移动到另一个类,注入到本类后,再从外部进行调用

无论是第一种还是第二种都有点恶心,有点像是帮spring擦屁股。

知道问题在哪,就好办了。 既然对象代理模式有问题,那我们就换掉代理模式,使用方法拦截的模式。

怎么解决

这是我的starter组件,已经开源了。

<dependency>
    <groupId>io.gitee.the-keyboard</groupId>
    <artifactId>spring-boot-starter-tx</artifactId>
    <version>0.1</version>   
</dependency>

引入starter后,事务就不会失效了。

包括this调用,final,private场景,事务也不会失效。

技术原理

源码地址: gitee.com/The-Keyboar…

优化版事务组件,核心代码如下

@Bean
public TransactionInterceptor transactionInterceptor() {
    TransactionAttributeSource transactionAttributeSource = new AnnotationTransactionAttributeSource(false);
    TransactionInterceptor interceptor = new TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource);
    Arounds arounds = AroundsImpl.getInstance();
    Pointcut pointcut = new AnnotationPointcut(null, Transactional.class);
    arounds.add(pointcut, new FromMethodInterceptor(interceptor));
    return interceptor;
}

用新的事务组件替代spring自带的事务组件

不管是this调用,private方法,final方法,事务都不会再失效了

为什么不会失效?以及几种常见的aop模式:接口代理(spring的jdk动态代理),子类代理(spring的cglib模式),子类拦截,方法拦截,下篇继续分享