原由:有次开发业务代码,事务方法A中存在不强依赖事务的逻辑,将改逻辑抽取方法B,然后再用this调用B方法。按照惯性思维,B方法不走事务了,以为大功告成;实则不然B方法执行仍然和A方法处于同一事物中,那么如何才能使B方法不处于A方法的事务下执行呢?
以下以第一个方法为A方法,第二个方法为B方法称呼
## 尝试1
根据spring事务传播机制,想当然在B方法加以下注解
@Transactional(propagation = Propagation.NOT_SUPPORTED)
业务代码如下
期待的结果为dept表插入数据失败,goods表插入数据成功,实际上如下图,都没有插入数据,A方法事务对两个方法都生效
## 尝试2
A调用B方法时,用另一个线程去调用
此时发现两个表中都插入成功,看过源码的兄弟大概知道一点是spring事务是基于aop,并且事务是和线程绑定的,原码见下图,所以开启新的线程会导致事务失效,所以两个表数据都新增成功
表中数据如下
## 尝试3
利用spring异步处理,启动类加上@EnableAsync注解开启异步处理,在B方法加上@Async注解然后this调用,想当然以为和new thread一样两个表都新增成功,然而并非我们期待的那样,都新增失败事务生效,业务代码如下
至于为什么@Async注解,没起作用感兴趣的可以深入研究下
## 尝试4
在3的基础上利用代理对象去调用B方法,在启动类上加上注解@EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)暴露代理对象,执行之后查看表中数据发现,两个表数据都新增成功,说明@Async注解开启了异步线程处理,所以上一步为啥没有开启异步线程应该有点思路了吧哈哈,业务代码如下:
## 尝试5
如果我不想开启新的线程也想达到B方法不处于A方法事务下,当然也有方法还是利用spring事务的传播机制进行处理,业务代码如下
此时dept表新增失败,goods表新增成功,说明B方法以非事务方式执行
## 总结
当我们本类内部务方法A调用另一个方法B时,如果想使A事务生效但是是B方法事务不生效可以有三种方式
1.手动新建线程调用B方法
2.暴露代理对象,开启spring异步处理,在B方法加上@Async注解,用代理对象调用B方法
3.利用事务的传播机制B方法加上@Transactional注解传播机制设置为NOT_SUPPORTED
可以根据个人的需要采取合适的方式去使用,希望能对你有所帮助!