【老王读Spring Transaction-4】Spring事务管理的核心原理——PlatformTransactionManager&TransactionStatus

前言

通过编程的方式实现一个事务管理的过程可以分为三步:

  1. begin: 获取连接
  2. commit: 提交事务(业务正常执行)
  3. rollback: 回滚事务(业务异常)

Spring 中通过 @Transactional 注解的方式实现了切面式的事务管理,其本质还是会经历上面三个步骤。

下面我们就来研究一下 Spring 中是怎么实现事务的管理的。

Spring 版本

spring-tx 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

Spring 中通过 PlatformTransactionManager 来实现事务的管理。
TransactionManager.png

PlatformTransactionManager

PlatformTransactionManager 是 Spring 事务实现的核心接口。
通常,我们会通过 @Transactional 的方式 或者 TransactionTemplate 编程式的方式来使用 PlatformTransactionManager

@Transactional 底层是通过 AOP 的方式来使用 PlatformTransactionManager 的

PlatformTransactionManager 提供了三个方法用来管理事务:

  1. getTransaction(TransactionDefinition)
  2. commit(TransactionStatus)
  3. rollback(TransactionStatus)

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();
}

TransactionStatus.png

DefaultTransactionStatus

DefaultTransactionStatus 是 TransactionStatus 接口的默认实现。它由 PlatformTransactionManager 使用,保存了 AbstractPlatformTransactionManager 内部需要的所有状态信息。

DefaultTransactionStatus.png

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.png

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;
    }
}

可以看到,处理流程如下:

  1. 通过 PlatformTransactionManager 获取到 TransactionStatus
  2. 在事务中执行业务方法
  3. 业务方法正常结束,则通过 PlatformTransactionManager 对 TransactionStatus 执行 commit
  4. 业务方法异常结束,则通过 PlatformTransactionManager 对 TransactionStatus 执行 rollback

TransactionTemplate 编程的方式来管理事务,在实际的开发中比较少用到。推荐使用的是 @Transactional 注解的方式来自动管理事务

@Transactional 注解的方式

@Transactional 的方式来自动管理事务,底层是通过 Spring AOP 来实现的。

前面在分析 @Transactional 的实现原理时 讲到:Spring 是通过 TransactionInterceptor 来自动实现事务拦截的。
TransactionInterceptor 会调用父类的 TransactionAspectSupport#invokeWithinTransaction() 方法来执行事务方法,代码如下:
TransactionAspectSupport.png

可以看到,@Transactional 的处理流程如下:

  1. 创建 TransactionInfo 对象,包含: TransactionStatus、PlatformTransactionManager 等信息
  2. 执行业务方法
  3. 业务方法正常结束,则执行 commit
  4. 业务方法异常结束,则执行 rollback

@Transactional 的处理流程和 TransactionTemplate#execute() 的流程是类似的。

TransactionAspectSupport 中关于事务的操作,都是通过 PlatformTransactionManager 来进行的,比如:TransactionAspectSupport#commitTransactionAfterReturning() 会调用 PlatformTransactionManager#commit() 方法。
这样 Spring AOP 就与 PlatformTransactionManager 衔接起来了。

小结

PlatformTransactionManager 是 Spring 事务实现的核心接口,它和 TransactionStatus 共同来完成事务的管理。
TransactionStatus 主要是用来获取事务的状态信息,而 PlatformTransactionManager 是基于事务状态信息来提交 或 回滚事务。

PlatformTransactionManager 提供了三个方法用来管理事务:

  1. getTransaction(TransactionDefinition)
  2. commit(TransactionStatus)
  3. rollback(TransactionStatus)

Spring 对事务的管理流程如下:

  1. 通过 PlatformTransactionManager 获取到 TransactionStatus
  2. 在事务中执行业务方法
  3. 业务方法正常结束,则通过 PlatformTransactionManager 对 TransactionStatus 执行 commit
  4. 业务方法异常结束,则通过 PlatformTransactionManager 对 TransactionStatus 执行 rollback
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王学源码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值