spring事务传播实现源码分析
本文只是对spring事务传播实现的流程进行简单的分析,如有不对之处请指出。
配置spring事务管理时,我们会使用DataSourceTransactionManager这个类,它继承了AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager实现了PlatformTransactionManager接口,PlatformTransactionManager接口是spring事务管理的基础接口,只有三个方法getTransaction()、commit()和rollback()。
通过注解@Transactional,我们就可以把事务交由spring管理。spring是通过代理的方式对其添加事务管理,在生成的代理对象中就会调用PlatformTransactionManager实现类的三个方法来获取事务、提交事务、回滚事务,从而达到事务管理的目的。其中获取事务即调用getTransaction()方法,改方法中就会对事务的传播做相应的处理。
1、getTransaction()方法
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction(); // 获取事务管理对象,从下面doGetTransaction()实现可以知道,这里是尝试获取已有的事务管理对象,这里已有的就是指“传播”来的事务。
..............................
if (isExistingTransaction(transaction)) { //判断该事务管理对象是否已经存在
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
..................................
// No existing transaction found -> check propagation behavior to find out how to proceed.
// 根据不同事务传播属性进行不同的处理
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition); // 新起一个事务
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
2、 doGetTransaction()方法
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// TransactionSynchronizationManager里面通过ThreadLocal变量保存了dataSource对应的ConnectionHolder ,如果ConnectionHolder存在且激活就表明有“传播”来的事务。
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
// 顺便提下,其它ORM框架就是通过TransactionSynchronizationManager.getResource(dataSource)获取数据库连接,以此到达事务交由spring管理的目的。
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
3、 isExistingTransaction()方法
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
//ConnectionHolder存在且激活就表明有“传播”来的事务。
return (txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive());
}
4、 doBegin()方法
// 这里是新起一个事务,为事务管理对象设置相应的值,包括ConnectionHolder、隔离等级、是否自动提交等,并把当前线程与ConnectionHolder和dataSource进行绑定。
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the session holder to the thread.
if (txObject.isNewConnectionHolder()) {
//把当前线程与ConnectionHolder和dataSource进行绑定,在上面的doGetTransaction()中就可以对应获取,即到达事务传播的目的。
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
DataSourceUtils.releaseConnection(con, this.dataSource);
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
spring事务传播实现源码分析的更多相关文章
- spring事务概念与获取事务时事务传播行为源码分析
一.事务状态:org.springframework.transaction.TransactionStatus isNewTransaction 是否是新事务 hasSavepoint 是否有保存点 ...
- Spring JPA实现逻辑源码分析总结
1.SharedEntityManagerCreator: entitymanager的创建入口 该类被EntityManagerBeanDefinitionRegistrarPostProcesso ...
- Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)
Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...
- spring boot 2.0 源码分析(一)
在学习spring boot 2.0源码之前,我们先利用spring initializr快速地创建一个基本的简单的示例: 1.先从创建示例中的main函数开始读起: package com.exam ...
- spring boot 2.0 源码分析(四)
在上一章的源码分析里,我们知道了spring boot 2.0中的环境是如何区分普通环境和web环境的,以及如何准备运行时环境和应用上下文的,今天我们继续分析一下run函数接下来又做了那些事情.先把r ...
- Spring中Bean命名源码分析
Spring中Bean命名源码分析 一.案例代码 首先是demo的整体结构 其次是各个部分的代码,代码本身比较简单,不是我们关注的重点 配置类 /** * @Author Helius * @Crea ...
- Spring Boot 自动配置 源码分析
Spring Boot 最大的特点(亮点)就是自动配置 AutoConfiguration 下面,先说一下 @EnableAutoConfiguration ,然后再看源代码,到底自动配置是怎么配置的 ...
- Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析
一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...
- Spring基础系列-AOP源码分析
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...
随机推荐
- mac home目录创建文件夹,修改权限
mac 是基于unix, 自带就有home目录,但是为空.home目录的默认所属用户是root wheel,mac默认的root账号所属用户是root admin,所以root也无法在home目录下创 ...
- PHP中的插件机制原理和实例
PHP项目中很多用到插件的地方,更尤其是基础程序写成之后很多功能由第三方完善开发的时候,更能用到插件机制,现在说一下插件的实现.特点是无论你是否激活,都不影响主程序的运行,即使是删除也不会影响. 从一 ...
- excel技巧--文本拆分合并
如果像上图那样将一单元格内拆分成同等大小的字词,可用如下步骤: 1.将该单元格的宽度缩至拆分词的大小: 2.选择同列的适当的单元格,用于填充拆分的字符: 3.点击“开始”-->填充-->两 ...
- XE5 Android 开发实现手机打电话和发短信 [转]
其实都可以通过intent和URI调用系统功能.Windows程序员可以理解成是ShellExecute.这个是万金油.可以有调用各种功能.后面会介绍. 1.短信息.很简单 方法a.不使用Intent ...
- DEBUG模式详解
1. 如果开启了DEBUG模式,那么以后我们修改了Django项目的代码,然后按下ctrl+s,那么Django就会自动的给我们重启项目,不需要手动重启.2. 如果开启了DEBUG模式,那么以后Dja ...
- ALGO-43_蓝桥杯_算法训练_A+B Problem
问题描述 输入A,B. 输出A+B. 输入格式 输入包含两个整数A,B,用一个空格分隔. 输出格式 输出一个整数,表示A+B的值. 样例输入 样例输出 数据规模和约定 -,,,<=A,B< ...
- 峰Redis学习(9)Redis 集群(概述)
第一节:Redis 集群概述 redis cluster是去中心化,去中间件的,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态.每个节点都和其他所有节点 ...
- spring cglib实现嵌套方法拦截
使用spring 的拦截器对方法进行拦截,不管是动态代理,还是cglib, 只能拦截到被代理对象的调用方法,对于被调用方法里再调用同一对象里的其他方法就无法拦截到,就是我们说的嵌套拦截,之前文章里提及 ...
- windows server 2008 R2 安装
微软服务器操作系统大致有: server 2000(简称2K),还有server 2003(2K3),server 2008(2K8),server 2000和2003是基于NT内核的,而2008是基 ...
- webview自总结
2,webview ---- 运行时不调用系统自带浏览器: 1,安卓webview post传值问题: 11,WebView基本功能(html5.文件下载和远程URL) 10,webview--网络超 ...