这几天都在分析Spring的源码实现,看到事务管理的部分

  我们知道事务的传播特性有下面几种,我标黄的就是最常用的3中传播特性, Sping在发生事务嵌套的时候,会依据内层事务的传播特性,来决定内层是事务的行为

  对于传播特性的处理,一定是在外层已经存在事务的情况下进行的, 使用了AOP事务管理 那么在执行外层方法前,进入代理的时候就会调用getTransaction(txAttr)方法来开启事务,此时因为还没有ConnectionHolder创建出来,所以一定会去创建Connection 和 ConnectionHolder 以及开启事务的,这个时候 spring不会关系外层方法对于的事务的传播特性,此时的传播特性也没有什么意义. 

  到了第二层,这个传播特性才开始起作用了,在外层已经有事务开启的情况下,本层的方法是开启新事务,还是加入上层的事务,还是报错,等等举动,就都取决于这个传播特性了.

  • PROPAGATION_MANDATORY  方法必须在事务中运行,如果没有事务就要抛出错误 MANDATORY 是强制的意思
  • PROPAGATION_NESTED   嵌套,外层有事务的情况下 如果内层要打开事务就打开事务嵌套运行,如果内层没有事务就加入到上层事务中去,嵌套事务是可以独立提交和回滚的 (对于jdbc Spring其实在内层没有开启新事务,只是在内层方法前设置了savepoint)
  • PROPAGATION_NEVER  表示这个方法不能运行在事务中,如果上下文有事务 就要抛出异常
  • PROPAGATION_NOT_SUPPORTED 表示当前方法运行的时候 如果有上下文事务,那么上下文事务会被挂起 等该方法执行结束,上下文事务恢复
  • PROPAGATION_REQUIRED  表示当前方法必须运行在事务中,如果上下文有事务就加入上下文事务;上下文没有事务,就启动一个新事务
  • PROPAGATION_REQUIRES_NEW  当前方法一定会启动自己的事务,如果有上下文事务,上下文事务会被挂起的 (对于jdbc  Spring在内层开启新事务(创建了新的Connection  内层事务是独立的开启 提交 回滚的)
  • PROPAGATION_SUPPORTS 表示当前方法不需要上下文事务,但是如果有上下文事务的话 还是可以在上下文事务里运行的
     
    对于不同的传播特性 做出不同的处理,这个逻辑所在的核心方法就是AbstractPlatformTransactionManager类中的handleExistingTransaction方法
看源码摘录:
     /**
* Create a TransactionStatus for an existing transaction.
*/
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException { //PROPAGATION_NEVER 就是不能再事务环境中运行 如果外层有事务了 就直接抛错
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
} //PROPAGATION_NOT_SUPPORTED 也表示不能运行在上下文事务中,但是不会抛出 会把外层事务挂起
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
//开始挂起外层事务 这会把外层事务的ConnectionHolder ,names isolation 等等属性存到suspendedResources 然后suspendedResources 存到
//本层事务对于的TransactionStatus对象里面
//然后会清除TransactionSynchronizationManager里面的ThreadLocal属性 包括线程绑定的ConnectionHolder ,于是本层dao方法中如果要访问数据库就不能取ThreadLocal里的Connection了
//得自己新建Connection,自然就实现了脱离外层事务的目的
//等到本层dao方法结束,进行commit的时候 会跳过doCommit方法 执行resume方法 恢复外层事务
Object suspendedResources = suspend(transaction); //newSynchronization 肯定是false
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);
} //PROPAGATION_REQUIRES_NEW 会在本层开启新的事务 挂起上层事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
//挂起上层事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
//开启本层新事务
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);//也是true
//创建txStatus对象 isNewTransaction是true
DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//执行conn.setAutoCommit(false) 以及ConnectionHolder状态设置,以及ConnectionHolder线程绑定
doBegin(transaction, definition);
//TransactionSynchronizationManager属性填充
prepareSynchronization(status, definition); return status;
}
catch (RuntimeException beginEx) {
//如果出异常 就恢复上层事务
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
catch (Error beginErr) {
resumeAfterBeginException(transaction, suspendedResources, beginErr);
throw beginErr;
}
} //PROPAGATION_NESTED 是嵌套,但是spring实现jdbc的嵌套并没有开启事务,而是通过设置savepoint来实现的
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
//如果允许使用savepoint来实现Nest
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
//不开启新事务 直接创建txStatus
DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
//创建savepoint
status.createAndHoldSavepoint();
return status;
}
else {
//如果不允许使用savepoint 那就和PROPAGATION_REQUIRES_NEW 是一样的 本层开启全新事务 区别在于 这里是没有对上层事务做挂起
//这种事情主要用在JTA事务
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
} // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
} //PROPAGATION_SUPPORTS 和 PROPAGATION_REQUIRED的情况 处理方式是一样的 也就是不做任何处理 直接生产TransactionStatus对象就返回了 本层直接加入上层事务
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
 
 

Spring各种传播特性源码实现的概览的更多相关文章

  1. spring事务传播实现源码分析

    转载. https://blog.csdn.net/qpfjalzm123/article/details/83717367 本文只是对spring事务传播实现的流程进行简单的分析,如有不对之处请指出 ...

  2. spring事务概念与获取事务时事务传播行为源码分析

    一.事务状态:org.springframework.transaction.TransactionStatus isNewTransaction 是否是新事务 hasSavepoint 是否有保存点 ...

  3. Spring 事物传播特性

    Spring 事物传播特性 这是Spring官方的定义 一共有7种 摘自源码省略了一部分 public interface TransactionDefinition { int PROPAGATIO ...

  4. Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)

    Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...

  5. Spring框架之beans源码完全解析

    导读:Spring可以说是Java企业开发里最重要的技术.而Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Oriented Programmin ...

  6. Spring框架之websocket源码完全解析

    Spring框架之websocket源码完全解析 Spring框架从4.0版开始支持WebSocket,先简单介绍WebSocket协议(详细介绍参见"WebSocket协议中文版" ...

  7. Spring框架之事务源码完全解析

    Spring框架之事务源码完全解析   事务的定义及特性: 事务是并发控制的单元,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务将逻辑相关的一组操作绑定在一 ...

  8. Spring框架之jms源码完全解析

    Spring框架之jms源码完全解析 我们在前两篇文章中介绍了Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Oriented Programmi ...

  9. Spring框架之spring-webmvc源码完全解析

    Spring框架之spring-webmvc源码完全解析 Spring框架提供了构建Web应用程序的全功能MVC模块.Spring MVC分离了控制器.模型对象.分派器以及处理程序对象的角色,支持多种 ...

随机推荐

  1. andriod系统裁剪心得

    亲们,,有人做过 将android系统总内存减少,并保持系统的稳定运行 方面的么?...比如将512M的内存换成256M,系统依然稳定运行,, 我目前,从三个方面下手,,,1.删减系统中不需要使用的a ...

  2. Learning WCF 书中的代码示例下载地址

    Learning WCF Download Example Code 第一个压缩文件LearningWCF.zip是VS2005创建的项目,不要下载这个. 建议下载VS2008版的,以及Media

  3. django 项目部署在 Apache 后, 设置二级域名(Apache虚拟主机 、 万网二级域名设置)

    上一篇文章简单说了怎么把django的项目部署到Apache上. 现在想弄个二级域名,也就是我原来有个域名 www.mysite.com,现在我想弄个 bbs.mysite.com ,该怎么做呢. 要 ...

  4. NopCommerce架构分析(转载)

    原文 一,NopCommerce架构分析之开篇 NopCommerce是.net开源项目中比较成熟的一款业务应用框架,也是电子商务系统中的典范.所以很想多学习一下里面的设计和实现方式. 二,NopCo ...

  5. Maven source jar get

    Maven作为项目管理的包,同时也能方便的将source-jar下载的本地,省去了每次到网上分别下载的问题. Maven下载Jar包同时下载源文件和文档 示例,在maven生成的工程里面:mvn ec ...

  6. linux内核--内核内存管理

    如题目所示,为什么要称作“内核内存管理”,因为内核所需要的内存和用户态所需要的内存,这两者在管理上是不一样的. 这篇文章描述内核的内存管理,用户态的内存管理在以后的文章中讲述. 首先简单的说明一下下面 ...

  7. python编写Mysql自动备份脚本

    1、先写一个python脚本 vim /opt/mysql_dump.py #!/usr/bin/env python# -*- coding:utf-8 -*-import osimport tim ...

  8. Servlet(2)

    一.伪代码演示Tomcat的内部代码运行 1).通过映射找到servlet-class的内容,字符串:com.gqx.servlet.FirstServlet 2).通过反射构造构造FirstServ ...

  9. MySQL添加外键时报错 ERROR 1215 (HY000): Cannot add foreign key constraint

    1.数据类型      2.数据表的引擎 数据表 mysql> show tables; +------------------+ | Tables_in_market | +--------- ...

  10. jquerymobile知识点:动态Grid的绑定以及刷新

    下面jquerymobile是ajax动态绑定和刷新的例子.直接上图以及代码. 下面是实例代码: //初始绑定 function GetInitBind(PageIndex, PageSize, sq ...