【老王读Spring Transaction-3】TransactionDefinition原理和源码解析

前言

前文在分析@Transactional是如何被解析的 时候讲到,@Transactional 配置的事务属性被解析出来之后,被放在了 RuleBasedTransactionAttribute 当中。

TransactionAttribute 是 Spring 中用来定义事务属性的接口,它继承自 TransactionDefinition

下面就来详细分析一下 TransactionDefinition 的作用。

版本约定

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

正文

首先看一下 TransactionDefinition 的类图:

TransactionAttribute.png

可以看到,TransactionAttribute 是 TransactionDefinition 的子接口,它是用来定义事务属性的。

详细的类图如下:

TransactionAttributeDetail.png

TransactionDefinition

定义 Spring 事务属性的接口。

注意: 只有在启用新事务时,isolation level(隔离级别)和 timeout 设置才会生效。

TransactionDefinition 的定义如下:

public interface TransactionDefinition {
     /**
      * 返回事务传播行为(propagation behavior)
      * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
      */
     default int getPropagationBehavior() {
          return PROPAGATION_REQUIRED;
     }

     /**
      * 返回事务隔离级别(isolation level)。  
      * 这个属性只适用于新启动的事务,即针对事务传播行为是 PROPAGATION_REQUIRED 或 PROPAGATION_REQUIRED_NEW 的情况
      * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
      */
     default int getIsolationLevel() {
          return ISOLATION_DEFAULT;
     }

     /** 返回事务超时时间。(单位:秒, 默认值: TIMEOUT_DEFAULT) */
     default int getTimeout() {
          return TIMEOUT_DEFAULT;
     }

     /**
      * 返回是否是只读事务。  
      * 只读标志适用于任何事务上下文,不管是事务操作还是非事务操作。
      * @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean)
      * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
      */
     default boolean isReadOnly() {
          return false;
     }

     /**
      * 返回此事务的名称(可以为空)。
      * 对于 Spring 的声明性事务,默认暴露的事务名称是 “类的完全限定名.方法名称”。
      * @see org.springframework.transaction.interceptor.TransactionAspectSupport
      * @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName()
      */
     @Nullable
     default String getName() {
          return null;
     }

}

TransactionDefinition 中还定义了事务传播行为事务隔离级别 的一些常量:

 /** 支持当前事务;如果不存在,则创建一个新的。(默认的事务传播行为)*/
 int PROPAGATION_REQUIRED = 0;

 /**
  * 支持当前事务;如果不存在,则以非事务方式执行。  
  * 注意: 它和没有事务执行是有区别的。需要谨慎使用!
  * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
  * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
  */
 int PROPAGATION_SUPPORTS = 1;

 /** 支持当前事务;如果当前不存在事务,则抛出异常。 */
 int PROPAGATION_MANDATORY = 2;

 /**
  * 创建一个新事务,并且挂起当前事务(如果当前事务存在的话)。
  * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
  */
 int PROPAGATION_REQUIRES_NEW = 3;

 /**
  * 不支持当前事务,始终以非事务方式执行。  
  * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
  */
 int PROPAGATION_NOT_SUPPORTED = 4;

 /** 不支持当前事务;如果当前事务存在,则抛出异常。 */
 int PROPAGATION_NEVER = 5;

 /**
  * 如果存在当前事务,则在嵌套事务中执行,否则,其行为与 PROPAGATION_REQUIRED 的行为类似。  
  * 注意:嵌套事务的实际创建只适用于特定的事务管理器,比如 DataSourceTransactionManager 在使用 JDBC 3.0 driver 时。
  * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
  */
 int PROPAGATION_NESTED = 6;
 
 /** 使用默认的事务隔离级别 */
 int ISOLATION_DEFAULT = -1;

 /** 读未提交。等同于: java.sql.Connection#TRANSACTION_READ_UNCOMMITTED */
 int ISOLATION_READ_UNCOMMITTED = 1;

 /** 读已提交。等同于: java.sql.Connection#TRANSACTION_READ_COMMITTED */
 int ISOLATION_READ_COMMITTED = 2;

 /** 可重复读。等同于: java.sql.Connection.TRANSACTION_REPEATABLE_READ */
 int ISOLATION_REPEATABLE_READ = 4;

 /** 等同于: java.sql.Connection#TRANSACTION_SERIALIZABLE */
 int ISOLATION_SERIALIZABLE = 8; 
 
 /** 默认的事务超时时间 */
 int TIMEOUT_DEFAULT = -1;

TransactionAttribute

TransactionAttribute 是 TransactionDefinition 的子接口,它增加了 rollbackOn() 方法,用于判断针对哪些异常进行事务回滚操作。

它有两个比较常用的实现类: DefaultTransactionAttributeRuleBasedTransactionAttribute

DefaultTransactionAttribute

DefaultTransactionAttribute 是 Spring 默认的事务属性实现,它只针对 RuntimeException 和 Error 进行回滚。

// DefaultTransactionAttribute#rollbackOn()
public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

RuleBasedTransactionAttribute

RuleBasedTransactionAttribute 继承了 DefaultTransactionAttribute。
它表示的是基于规则的 TransactionAttribute,可以用于判断针对指定的异常是否需要回滚。

// 获胜规则是最浅的规则(即继承层次结构中最接近异常的规则)
public boolean rollbackOn(Throwable ex) {
    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;

    if (this.rollbackRules != null) {
        for (RollbackRuleAttribute rule : this.rollbackRules) {
            int depth = rule.getDepth(ex);
            if (depth >= 0 && depth < deepest) {
                deepest = depth;
                winner = rule;
            }
        }
    }

    // User superclass behavior (rollback on unchecked) if no rule matches.
    if (winner == null) {
        return super.rollbackOn(ex);
    }

    return !(winner instanceof NoRollbackRuleAttribute);
}

可以看到,RuleBasedTransactionAttribute 用于判断针对指定的异常是否需要进行回滚。
如果异常类存在继承关系,它也是支持的。
特别的,如果没有指定回滚规则,那么会使用 DefaultTransactionAttribute 来进行回滚判断。

小结

TransactionDefinition 是用来定义事务属性的。
TransactionAttributeTransactionDefinition 的子接口,它还有一个 rollbackOn() 方法,当出异常时,用于判断是否需要进行事务回滚。

TransactionDefinition 有两个比较常用的实现类 DefaultTransactionAttributeRuleBasedTransactionAttribute
Spring 在读取了 @Transactional 注解之后,会将里面的事务属性保存在 RuleBasedTransactionAttribute 中。

RuleBasedTransactionAttribute 用于判断针对指定的异常是否需要进行回滚,如果没有指定回滚规则,那么会使用 DefaultTransactionAttribute 来进行回滚判断。


了解更多源码知识,请点击视频讲解:
SpringIoC源码由浅入深 : https://edu.51cto.com/sd/68e86


如果本文对你有所帮助,欢迎点赞收藏
有关 Spring 源码方面的问题欢迎留言一起交流…

阅读更多文章,请关注公众号: 老王学源码
gzh_b2.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老王学源码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值