Transactional注解事务解析
@Transactional注解的事务逻辑是通过Aop代理实现的。生成代理的过程比较复杂,这里只讨论事务的核心逻辑。
1、spring boot的事务管理器
spring boot提供了PlatformTransactionManager类来管理事务

可以看到,spring boot只提供了接口,可以允许不同的数据源进行实现。
因为我平时主要使用的是jdbc,因此主要看jdbc的实现类DataSourceTransactionManager。

DataSourceTransactionManager类继承了AbstractPlatformTransactionManager抽象类,而AbstractPlatformTransactionManager抽象类又实现了PlatformTransactionManager接口,类图关系如下:

2、几个重要的方法
在事务的执行过程中,一般的阶段为:开始事务->执行sql->提交事务/回滚事务。
所以当我们看DataSourceTransactionManager类时,有几个方法是需要注意的:doBegin,doCommit,doRollback

另外还有其父类AbstractPlatformTransactionManager的getTransaction和startTransaction方法

现在先记着这几个方法,后面再验证是否是使用到了这几个方法。
3、核心代码位置
从上面的几个方法中,我们可以大致推测,getTransaction和startTransaction以及doBegin是用于开启事务的,doCommit和doRollback用于事务的提交和回滚。
实际上,
getTransaction方法内部调用了startTransaction,而startTransaction内部调用的doBegin
我们开头提到,@Transactional的事务是通过Aop代理实现的,那么执行的步骤就应该如下所示:

那么,是哪里拦截了@Transactional修饰的方法(目标方法),并调用了开启事务的方法?
因为其代理生成的逻辑比较复杂,这里只找其核心代码。
在idea中,我们将源码下载下来,并使用ctrl加鼠标左键依次点击开启事务的方法,就能发现,其调用的核心代码在TransactionAspectSupport类中的createTransactionIfNecessary方法中:


而createTransactionIfNecessary方法又是由invokeWithinTransaction方法调用的

invokeWithinTransaction方法其实就是核心代码
4、核心代码分析
上面说了invokeWithinTransaction方法就是核心代码,然后我们只取其中主要的部分进行分析:

1 | TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); |
在上述代码中,执行步骤分别是:
- 执行
createTransactionIfNecessary方法开启事务, - 使用
try来执行invocation.proceedWithInvocation(),这个就是执行目标方法 - 如果
try的执行出现异常,捕获异常,并调用completeTransactionAfterThrowing回滚 - 在
finally时调用cleanupTransactionInfo方法清除当前节点的事务信息 - 最后调用
commitTransactionAfterReturning提交事务
ps:
completeTransactionAfterThrowing方法中,并不是一定就会回滚,而是看捕获的异常是否是@Transactional中声明的异常的子类,如果是的话就回滚,不是的话就提交
接下来我们打断点看看具体的流程:
首先进入了createTransactionIfNecessary方法,如下:

然后createTransactionIfNecessary调用了getTransaction方法

getTransaction方法又调用了startTransaction方法

startTransaction方法调用了doBegin方法

然后我们可以看到,在doBegin方法里,将事务的提交方式改成了手动提交

然后回到invokeWithinTransaction方法,并调用目标函数

最后进行事务的提交






