Spring 事务源码(五):事务的传播特性

1、事务传播特性

  Springs事务传播特性:
 
名称
解释
 
REQUIRED
支持当前事务,如果当前没有事务,就新建一个事务。 Spring 默认的事务传播特性
支持外层事务
SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行
MANDATORY
支持当前事务,如果当前没有事务,则抛出异常
REQUIRES_NEW
新建事务,如果当前存在事务,则事务挂起,新增一个事务,新建的事务和当前的事务没有任何关系,是两个独立的事务,外层的事务失败回归后,不能回滚内层事务的运行结果,内层事务失败抛出异常,外层事务有捕获,也能不回滚事务操作
不支持外层事务
NOT_SUPPORTED
不执行当前事务;而是总是执行非事务
NEVER
以非事务方式执行,如果当前存在事务,则抛出异常
NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作
嵌套事务
 

2、外层传播特性REQUIRED为例分析Spring事务传播特性

  外层的传播特性为REQUIRED,首先外层会新建一个事务TransactionInfo,如果已存在事务,那么内存的事务该如何执行?我们接着往下分析。

2.1、已存在事务执行流程入口

  AbstractPlatformTransactionManager#getTransaction 获取事务状态核心伪代码:
 1 // 获取事务信息
 2 public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
 3 
 4   // 若不指定事务定义,则使用默认的事务定义StaticTransactionDefinition
 5   TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
 6 
 7   // 获取数据源对象 DataSourceTransactionObject
 8   Object transaction = doGetTransaction();
 9   boolean debugEnabled = logger.isDebugEnabled();
10 
11   // 若已存在事务,按已存在事务流程执行
12   if (isExistingTransaction(transaction)) {
13     return handleExistingTransaction(def, transaction, debugEnabled);
14   }
15 }

1、创建数据源对象

  AbstractPlatformTransactionManager#doGetTransaction 获取数据源属性对象核心代码:
 1 // 创建数据源属性对象,并填充属性
 2 protected Object doGetTransaction() {
 3    // 创建一个数据源事务对象
 4    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
 5    // 是否允许当前事务设置保存点
 6    txObject.setSavepointAllowed(isNestedTransactionAllowed());
 7    // 对于内层被增强方法而言,数据源对应的jdbc连接在创建新事务时, 在事务同步管理器中已经完成初始化,此处事务管理器的jdbc连接不为空
 8    ConnectionHolder conHolder =
 9          (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
10    txObject.setConnectionHolder(conHolder, false);
11    // 返回事务对象
12    return txObject;
13 }

  创建数据源属性对象,并设置是否允许当前事务设置保存点,并获取数据源对应的jdbc连接,设置进数据源属性对象中。

2、是否为已存在的事务

  DataSourceTransactionManager#isExistingTransaction 是否已存在事务核心代码
1 protected boolean isExistingTransaction(Object transaction) {
2    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
3    // 判断数据源事务对象中是否有连接持有器,并且事务处理激活状态
4    return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
5 }

3、执行已存在事务流程概览

3.1、核心流程图

3.2、核心伪代码

  AbstractPlatformTransactionManager#handleExistingTransaction 执行已存在事务核心伪代码:
 1 private TransactionStatus handleExistingTransaction(
 2       TransactionDefinition definition, Object transaction, boolean debugEnabled)
 3       throws TransactionException {
 4 
 5     // 当前事务行为为PROPAGATION_NEVER, 不支持事务,但是当前又存在一个事务,所以抛出异常
 6    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
 7       throw new IllegalTransactionStateException(
 8             "Existing transaction found for transaction marked with propagation 'never'");
 9    }
10 
11    // 当前事务行为为PROPAGATION_NOT_SUPPORTED, 挂起已经存在的事务, 以非事务状态运行
12    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
13       // 挂起当前事务并返回挂起的资源持有器
14       Object suspendedResources = suspend(transaction);
15       boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
16       // 创建一个新的非事务状态(保存了上一个存在事务状态的属性)
17       return prepareTransactionStatus(
18             definition, null, false, newSynchronization, debugEnabled, suspendedResources);
19    }
20 
21     // 当前事务行为为PROPAGATION_REQUIRES_NEW,挂起已经存在的事务,开启一个新事务
22    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
23       if (debugEnabled) {
24          logger.debug("Suspending current transaction, creating new transaction with name [" +
25                definition.getName() + "]");
26       }
27       // 挂起当前事务并返回挂起的资源持有器
28       SuspendedResourcesHolder suspendedResources = suspend(transaction);
29       try {
30          // 创建事务(保存了上一个存在事务状态的属性)
31          return startTransaction(definition, transaction, debugEnabled, suspendedResources);
32       }
33       catch (RuntimeException | Error beginEx) {
34          resumeAfterBeginException(transaction, suspendedResources, beginEx);
35          throw beginEx;
36       }
37    }
38   
39    // 当前事务行为PROPAGATION_NESTED,判断是否允许嵌套事务,不允许,抛异常;
40    // 否则,判断是否使用保存点执行Nest事务,若使用保存点,创建事务状态对象,并为当前事务创建一个保存点,返回事务状态对象;
41    // 若不使用保存点执行Nest事务,创建事务执行
42    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
43       // 支持嵌套事务,不允许就报异常
44       if (!isNestedTransactionAllowed()) {
45          throw new NestedTransactionNotSupportedException(
46                "Transaction manager does not allow nested transactions by default - " +
47                "specify 'nestedTransactionAllowed' property with value 'true'");
48       }
49 
50       // 是否使用保存点执行nest事务,默认为true
51       if (useSavepointForNestedTransaction()) {
52          // 如果没有可以使用保存点的方式控制事务回滚,那么在嵌入式事务的建立初始保存点
53          DefaultTransactionStatus status =
54                prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
55          // 为事务设置一个回退点
56          status.createAndHoldSavepoint();
57          return status;
58       }
59       else {
60          // 不使用保存点的操作
61          return startTransaction(definition, transaction, debugEnabled, null);
62       }
63    }
64     
65    // 若为REQUIRED
66    // 事务是否需要同步标识
67    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
68    // 创建事务状态对象,newTransaction标识设置为false,标识不是一个新事务
69    return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
70 }
1、内层传播特性为NEVER
  当前事务行为为PROPAGATION_NEVER, 不支持事务,但是当前又存在一个事务,所以抛出异常
2、内层传播特性为NOT_SUPPORTED
  当前事务行为为PROPAGATION_NOT_SUPPORTED, 挂起已经存在的事务, 以非事务状态运行
3、内层传播特性为REQUIRES_NEW
  当前事务行为为PROPAGATION_REQUIRES_NEW,挂起已经存在的事务,开启一个新事务
4、内层传播特性为NESTED
  当前事务行为PROPAGATION_NESTED,判断是否允许嵌套事务,不允许,抛异常;
  否则,判断是否使用保存点执行Nest事务,若使用保存点,创建事务状态对象,并为当前事务创建一个保存点,返回事务状态对象;
  若不使用保存点执行Nest事务,开启一个新事务执行
5、内层传播特性为REQUIRED
  当前事务行为PROPAGATION_REQUIRED,创建事务状态对象,newTransaction标识设置为false,标识不是一个新事务,并返回事务状态对象。不是一个新事务代表,jdbc连接用的是同一个,在异常未捕获时,若发生回滚则一起回滚。
posted @ 2023-01-04 20:35  无虑的小猪  阅读(108)  评论(0编辑  收藏  举报