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

Posted 老王学源码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了老王读Spring Transaction-4Spring事务管理的核心原理——PlatformTransactionManager&TransactionStatus相关的知识,希望对你有一定的参考价值。

@TOC

前言

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

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

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

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

Spring 版本

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

正文

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

PlatformTransactionManager

PlatformTransactionManager 是 Spring 事务实现的核心接口。
通常,我们会通过 @Transactional 的方式 或者 TransactionTemplate 编程式的方式来使用 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 接口主要是通过 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;
    

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

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

@Transactional 注解的方式

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

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

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

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

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

以上是关于老王读Spring Transaction-4Spring事务管理的核心原理——PlatformTransactionManager&TransactionStatus的主要内容,如果未能解决你的问题,请参考以下文章

老王读Spring IoC-5Spring IoC 小结——控制反转依赖注入

老王读Spring IoC-2Spring IoC之BeanDefinition扫描注册的原理

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

老王读Spring Transaction从EnableTransactionManagement顺藤摸瓜,研究@Transactional的实现原理

老王读Spring Transaction-6spring-tx与DataSource连接池整合的原理

#yyds干货盘点# 老王读Spring AOP-4Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析