@TOC
前言
通过编程的方式实现一个事务管理的过程可以分为三步:
Spring 中通过 @Transactional 注解的方式实现了切面式的事务管理,其本质还是会经历上面三个步骤。
下面我们就来研究一下 Spring 中是怎么实现事务的管理的。
Spring 版本
spring-tx 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)
正文
Spring 中通过 PlatformTransactionManager 来实现事务的管理。
PlatformTransactionManager
PlatformTransactionManager 是 Spring 事务实现的核心接口。通常,我们会通过 @Transactional 的方式 或者 TransactionTemplate 编程式的方式来使用 PlatformTransactionManager。
@Transactional 底层是通过 AOP 的方式来使用 PlatformTransactionManager 的
PlatformTransactionManager 提供了三个方法用来管理事务:
PlatformTransactionManager 的源码如下:
public interface PlatformTransactionManager extends TransactionManager { /** * 根据指定的事务传播行为,返回当前活动的事务或创建新事务。 * 注意: 隔离级别 或 timeout 等参数只会应用到新开启的事务上,因此,如果是加入到当前活动事务时,这些参数将会被忽略。 * @param TransactionDefinition 用于描述 事务传播行为、隔离级别、timeout 等 * @return TransactionStatus 表示当前事务 * @see TransactionDefinition#getPropagationBehavior * @see TransactionDefinition#getIsolationLevel * @see TransactionDefinition#getTimeout */ TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException; /** * 提交给定的 TransactionStatus。 * 如果事务已通过编程方式标记为 rollback-only,将会执行回滚。 * 如果事务不是一个新开启的事务,则忽略本次提交操作(因为事务可能嵌套,嵌套在内部的事务在执行 commit 操作时,是不需要真正执行 commit 的)。 * @param getTransaction() 方法返回的 TransactionStatus 对象 */ void commit(TransactionStatus status) throws TransactionException; /** * 回滚给定的 TransactionStatus。 * 如果事务不是新开启的事务,则只将事务标记为 rollback-only。 * @param getTransaction() 方法返回的 TransactionStatus 对象 */ void rollback(TransactionStatus status) throws TransactionException; }PlatformTransactionManager#commit() 方法会被 TransactionAspectSupport#commitTransactionAfterReturning() 调用,这样就和 Spring AOP 衔接起来了。
PlatformTransactionManager 接口主要是通过 AbstractPlatformTransactionManager 来实现的。 AbstractPlatformTransactionManager 是实现 Spring 标准事务工作流的抽象基类,它是 DataSourceTransactionManager、JtaTransactionManager 等具体的平台事务管理器的基础。
TransactionStatus
TransactionStatus接口
TransactionStatus 能够获取事务的状态信息,它为事务代码提供了一种控制事务执行和查询事务状态的简单方法。 比如:它可以获取到当前是否是一个新开启的事务、事务有没有完成 等
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable { @Override boolean isNewTransaction(); boolean hasSavepoint(); // 这里可以控制事务执行的行为。其他方法都是获取事务的状态信息。 @Override void setRollbackOnly(); @Override boolean isRollbackOnly(); void flush(); @Override boolean isCompleted(); }DefaultTransactionStatus
DefaultTransactionStatus 是 TransactionStatus 接口的默认实现。它由 PlatformTransactionManager 使用,保存了 AbstractPlatformTransactionManager 内部需要的所有状态信息。
DefaultTransactionStatus 的构造函数如下:
public DefaultTransactionStatus( @Nullable Object transaction, boolean newTransaction, boolean newSynchronization, boolean readOnly, boolean debug, @Nullable Object suspendedResources) { this.transaction = transaction; // 当前事务对象(可为 null) this.newTransaction = newTransaction; // 是否需要新开启一个事务 this.newSynchronization = newSynchronization; // 是否需要开启新的事务同步 this.readOnly = readOnly; // 是否只读 this.debug = debug; this.suspendedResources = suspendedResources; // 当前挂起的事务(可为 null) }Spring 在每进入一个 @Transactional 方法时,都会创建一个 TransactionStatus 对象: DefaultTransactionStatus,用于记录本次事务的状态信息。 TransactionStatus 可以代表新事务,也可以代表现有的事务。
TransactionStatus 与 PlatformTransactionManager 结合使用
TransactionStatus 可以获取事务的状态信息,但是它并不负责事务的管理(提交 or 回滚)。 Spring 是通过 PlatformTransactionManager 来实现事务的管理的,其中提交 或 回滚事务都是以 TransactionStatus 做为入参的。
PlatformTransactionManager 管理事务的两种使用方式
PlatformTransactionManager 提供了事务管理的能力,而 Spring 提供了两种方式来调用 PlatformTransactionManager 来实现事务管理:一是,@Transactional 注解的方式;二是,TransactionTemplate 编程的方式。
TransactionTemplate 编程的方式
使用 TransactionTemplate 编程的方式来使用事务的话,可以使用类似如下的代码:
transactionTemplate.execute(new TransactionCallbackWithoutResult(){ protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { String sql = "insert into t_stu(id,name) values(?,?)"; jdbcTemplate.update(sql,1,"张三"); } });很显然,这样方式是使用了模板方法的模式,让 TransactionTemplate 去执行具体的事务管理操作,用户只需要填充业务代码就可以了。
TransactionTemplate#execute() 的源码如下:
// TransactionTemplate#execute() public <T> T execute(TransactionCallback<T> action) throws TransactionException { if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); T result; try { // 在事务中执行业务操作 result = action.doInTransaction(status); } catch (RuntimeException | Error ex) { // 判断是否要对 RuntimeException 和 Error 进行回滚 rollbackOnException(status, ex); throw ex; } catch (Throwable ex) { // 判断是否要对 Throwable 进行回滚 rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } // 业务操作正常结束,则执行 commit 操作 this.transactionManager.commit(status); return result; } }可以看到,处理流程如下:
TransactionTemplate 编程的方式来管理事务,在实际的开发中比较少用到。推荐使用的是 @Transactional 注解的方式来自动管理事务
@Transactional 注解的方式
@Transactional 的方式来自动管理事务,底层是通过 Spring AOP 来实现的。
前面在分析 @Transactional 的实现原理时 讲到:Spring 是通过 TransactionInterceptor 来自动实现事务拦截的。 TransactionInterceptor 会调用父类的 TransactionAspectSupport#invokeWithinTransaction() 方法来执行事务方法,代码如下:
可以看到,@Transactional 的处理流程如下:
@Transactional 的处理流程和 TransactionTemplate#execute() 的流程是类似的。
TransactionAspectSupport 中关于事务的操作,都是通过 PlatformTransactionManager 来进行的,比如:TransactionAspectSupport#commitTransactionAfterReturning() 会调用 PlatformTransactionManager#commit() 方法。 这样 Spring AOP 就与 PlatformTransactionManager 衔接起来了。
小结
PlatformTransactionManager 是 Spring 事务实现的核心接口,它和 TransactionStatus 共同来完成事务的管理。 TransactionStatus 主要是用来获取事务的状态信息,而 PlatformTransactionManager 是基于事务状态信息来提交 或 回滚事务。
PlatformTransactionManager 提供了三个方法用来管理事务:
Spring 对事务的管理流程如下: