这几天都在分析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. 转:三十二、Java图形化界面设计——布局管理器之CardLayout(卡片布局)

    转:http://blog.csdn.net/liujun13579/article/details/7773945 卡片布局能够让多个组件共享同一个显示空间,共享空间的组件之间的关系就像一叠牌,组件 ...

  2. UVA_1025_A_Spy_in_the_Metro_(动态规划)

    描述 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...

  3. java线程(2)-线程间通信

    方法一 通过访问共享变量的方式(注:需要处理同步问题) 方法二 通过管道流 其中方法一有两种实现方法,即 方法一a)通过内部类实现线程的共享变量  public class Innersharethr ...

  4. 老的acm & oj学习站点

    1.网易小鱼博客 http://gisyhy.blog.163.com/blog/#m=0&t=1&c=fks_087069086082087064085081082095085084 ...

  5. Centos6.4 设置开机自动以某个非root用户启动脚本

    开机自动运行脚本,可以将脚本的执行命令放在 /etc/rc.d/rc.local 文件中,但是这样开机自动运行这个脚本的用户默认为root. 如果想以某个非root用户运行脚本,可以使用如下命令: s ...

  6. (转载)Flash Number 数据类型

    (转载)http://www.g168.net/txt/flash/learningactionscript/00001183.html Number 数据类型 Number 数据类型是双精度浮点数. ...

  7. Devexpress 之gridControl双击行事件

    MouseDown事件 protected internal void gridControl1_MouseDown(object sender, MouseEventArgs e) { DevExp ...

  8. MySqlCommand, MySqlParameter and "LIKE" with Percent Symbol

    //Wrong way MySqlCommand cmd = oldDb.GetSqlStringCommand(CommandType.Text,"SELECT * _ FROM user ...

  9. 切换Oracle数据库实例

    如果多个实例,需要切换可以采用以下命令: export ORACLE_SID=SID

  10. Unity3d BTDF实时折射模拟有粗糙度的半透明物体

    折射的原理是运用BTDF的一个球形高斯近似 需要考虑折射光的来源,一般会想到用环境贴图(IBL)或者grab texture,但是折射光不全都来自一个平面,所以选择环境贴图来作为折射光.这个效果主要是 ...