首页 > 编程语言 >Spring 事务源码(五):事务的传播特性

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

时间:2023-01-04 20:45:15浏览次数:45  
标签:definition 事务 transaction Spring PROPAGATION 源码 当前 debugEnabled

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连接用的是同一个,在异常未捕获时,若发生回滚则一起回滚。

标签:definition,事务,transaction,Spring,PROPAGATION,源码,当前,debugEnabled
From: https://www.cnblogs.com/RunningSnails/p/17025931.html

相关文章

  • 重新编译gluster_exporter源码,构建镜像
    1.githubhttps://github.com/ofesseler/gluster_exporter 2.dockerfileFROMgolang:1.17ENVGO111MODULE=on\GOPROXY="https://goproxy.cn,direct"COPYglus......
  • 重新编译keepalived-exporter源码,构建镜像
    1.githubhttps://github.com/mehdy/keepalived-exporter 2.dockerfileFROMgolang:1.17ENVGO111MODULE=on\GOPROXY="https://goproxy.cn,direct"COPYkeepa......
  • SpringBoot yml配置文件引入实体类赋值
    @Value()直接使用注解赋值@ConfigurationProperties()注解引入yml文件配置实体类中的属性,注意:属性名字必须相同没有默认为null这里的名字和年龄相互对应......
  • Spring Boot中@Async的作用
    importorg.springframework.context.annotation.AnnotationConfigApplicationContext;importorg.springframework.context.annotation.Bean;importorg.springframewo......
  • Spring注解运行时抛出null
    关于Spring的注解其实不难,大致需要以下几个流程:一、配置Spring的注解支持1<?xmlversion="1.0"encoding="UTF-8"?>2<beansxmlns="http://www.springframework.o......
  • springboot 连接 mqtt,操作数据库时mqtt断开连接
    主要原因,程序异常导致连接断开第一种,普通类注入bean,为空。学过spring应该知道,这必然为空https://blog.csdn.net/qq_41249513/article/details/108465477https://blog.c......
  • Spring Boot整合Web项目常用功能详解
    这篇文章主要介绍了SpringBoot整合Web项目常用功能详解,在Web应用开发过程中,可以通过SpringBoot的Starter来将这些常用功能进行整合与集中维护,以达到开箱即用的目的。,需......
  • Spring Boot内置的一些工具类
    1、断言Assert工具类//要求参数object必须为非空(NotNull),否则抛出异常,不予放行//参数message参数用于定制异常信息。voidnotNull(Objectobject,Stringmessage......
  • Spring MVC无法获取ajax POST的参数和值
    一、怎么会这个样子很简单的一个想法,ajax以POST的方式提交一个表单,SpringMVC解析。然而一次次的打印null折磨了我整整一天……最后的解决现在看来是很明显的问题,“只是......
  • SpringBoot配置文件中spring
    SpringBoot配置文件中spring.profiles.active配置详解现象:在开发的时候测试和生产配置不一样每次加配置都需要更新生产原因:不方便解决:添加多套配置知识库:1、多环......