前置知识
事务的执行步骤如下:
- 获取事务管理器
- 创建事务
- 执行目标方法
- 捕捉异常,如果出现异常进行回滚
- 提交事务
1 | public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean { |
接下来,详细看一下事务的创建过程。
TransactionManager
事务管理器是Srping对事务进行管理的核心,PlatformTransactionManager里面定义了获取事务、提交事务、回滚事务的接口,不同的数据源可以有自己的实现,比如常见的JDBC数据源事务管理器DataSourceTransactionManager以及分布式事务管理器JtaTransactionManager:
PlatformTransactionManager
1 | public interface PlatformTransactionManager extends TransactionManager { |
TransactionStatus
PlatformTransactionManager的getTransaction返回的是TransactionStatus,TransactionStatus是一个接口,主要的实现在DefaultTransactionStatus中:
1 |
|
TransactionInfo
事务的创建方法createTransactionIfNecessary返回的是TransactionInfo对象,后续回滚事务、提交事务等操作,传入的都是TransactionInfo这个对象,它是TransactionAspectSupport的内部类,对事务管理器transactionManager、事务属性transactionAttribute、事务的状态transactionStatus等事务的相关信息进行了封装:
1 | /** |
事务的创建
事务的创建分为两大部分:
- 调用事务管理器的getTransaction获取事务状态,返回的是TransactionStatus类型的对象
- 预处理事务,进行事务相关信息的封装以及事务和线程的绑定,返回的是TransactionInfo对象
1 | public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean { |
获取事务状态
事务状态获取是调用PlatformTransactionManager事务管理器的getTransaction获取的,具体实现在AbstractPlatformTransactionManager中:
- 调用doGetTransaction方法获取事务,它是一个抽象方法,需要子类实现,数据源的不同具体的实现类也不同,接下来以常见的DataSourceTransactionManager为例,查看获取事务的具体实现逻辑
- 当前线程经存在事务,判断方式是通过当前线程是否持有数据库连接并且事务处于活跃状态
- 如果存在事务,需要根据事务传播行为进行不同的处理
- 当前线程不存在事务
- 如果事务的传播行为是PROPAGATION_MANDATORY,当前线程没有事务会抛出异常
- 如果传播行为是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED,先挂起一个空事务,然后新建事务
- 其他情况,调用prepareTransactionStatus创建TransactionStatus并返回
1 | public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable { |
doGetTransaction获取事务
DataSourceTransactionManager实现了doGetTransaction获取事务的方法:
- 创建DataSourceTransactionObject对象,它是DataSourceTransactionManager内部类,持有一个ConnectionHolder对象,里面记录了数据库的连接
- 调用obtainDataSource获取数据源
- 从ThreadLocal中获取当前线程对应的Map资源数据集合,根据第2步中获取到的数据源从Map中获取对应的ConnectionHolder,也就是说当前线程绑定了某个数据源的连接,从ThreadLocal获取到数据库连接之后,将数据库连接设置到DataSourceTransactionObject中
1 | public class DataSourceTransactionManager extends AbstractPlatformTransactionManager |
TransactionSynchronizationManager
TransactionSynchronizationManager中保存了线程绑定的各种信息:
1 | public abstract class TransactionSynchronizationManager { |
isExistingTransaction是否存在事务
isExistingTransaction同样在DataSourceTransactionManager中实现,具体是是通过DataSourceTransactionObject是否持有数据库连接并且事务处于活跃状态来判断是否存在事务的:
1 | public class DataSourceTransactionManager extends AbstractPlatformTransactionManager |
handleExistingTransaction当程已存在事务情况下的处理
在当前线程已存在事务的情况下:
- 如果事务传播行为设是PROPAGATION_NEVER,表示以非事务的方式执行,如果当前存在事务,将抛出异常
- 如果事务的传播行为是PROPAGATION_NOT_SUPPORTED,表示以非事务的方式执行,如果当前存在事务,则挂起当前的事务,不使用事务
- 如果事务的传播行为是PROPAGATION_REQUIRES_NEW,需要挂起当前事务,创建一个自己的事务
- 如果事务的传播行为是PROPAGATION_NESTED,判断是否使用保存点
- 如果是使用嵌套事务
- 如果不是,开启一个新事务
- 非以上四种情况,使用当前的事务,调用prepareTransactionStatus方法创建TransactionStatus
1 | public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable { |
prepareTransactionStatus创建TransactionStatus
prepareTransactionStatus用于创建TransactionStatus,具体创建的是DefaultTransactionStatus类型的:
1 | public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable { |
suspend挂起事务
挂起事务其实是将当前事务的相关设置清除,并解绑当前线程对应的数据库连接:
1 | public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable { |
startTransaction新建事务
startTransaction用于开启一个新事务,在AbstractPlatformTransactionManager中实现:
- 创建TransactionStatus,可以看到在构造函数中传入了事务定义、当前事务、是否新建事务(置为了true)、是否同步、是否debug、挂起的事务这些参数
- 调用doBegin方法设置事务的一些信息
1 | public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable { |
doBegin方法在DataSourceTransactionManager中实现:
- 判断当前事务是否持有数据库连接获取事务与数据库的同步状态为true,从数据源中新建一个数据库连接,并与当前事务绑定
- 如果开启了自动提交,将自动提交置为false
- 如果是新创建的连接,将数据库连接ConnectionHolder绑定到当前线程
1 | // DataSourceTransactionManager实现了doBegin |
事务预处理
- 创建TransactionInfo事务信息,它是TransactionAspectSupport的内部类,将事务管理器transactionManager、事务属性transactionAttribute、事务的状态transactionStatus等事务相关的信息进行了封装,并实现了将事务绑定到当前线程的方法
- 调用TransactionInfo的bindToThread方法将事务与当前线程绑定,是通过ThreadLocal实现的
1 | public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean { |
总结
参考
Spring版本:5.2.5.RELEASE