过时的八股文
”哪些场景会导致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模式),子类拦截,方法拦截,下篇继续分享