写在前面

  由于实现事务功能的方式各不相同,Spring进行了统一的抽象,形成了PlatformTransactionManager事务管理器顶级接口(平台事务管理器),事务的提交、回滚等操作全部交给它来实现

  先来看下三大接口

    • PlatformTransactionManager : 事务管理器

    • TransactionDefinition : 事务的一些基础信息,如超时时间、隔离级别、传播属性等

    • TransactionStatus : 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚

  一般我们给事务管理器的默认实现为DataSourceTransactionManager

    <!-- 事务管理器配置 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

DataSourceTransactionManager(事务管理器接口定义PlatformTransactionManager)

PlatformTransactionManager

  • AbstractPlatformTransactionManager

    •   DataSourceTransactionManager(重点)
    •   HibernateTransactionManager
    •   JpaTransactionManager
public interface PlatformTransactionManager {
//获取一个具体的事务状态信息
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
//提交一个事务状态信息
void commit(TransactionStatus status) throws TransactionException;
//回滚一个事务状态信息
void rollback(TransactionStatus status) throws TransactionException;
}

获取Object transaction:

  大体内容就是先获取上述说明(TransactionStatus)的Object transaction,判断当前事务是否已存在,如果存在则进行事务的传播属性处理,后面详细说明,如果不存在new DefaultTransactionStatus,新创建一个事务,同时使用Object transaction开启事务。 分成了几个过程:

  

  1. 获取Object transaction:不同的事务管理器获取不同的Object transaction

  DataSourceTransactionManager就是获取上述的DataSourceTransactionObject

  从当前线程中获取绑定的ConnectionHolder,可能为null,如果为null,则会在下一个开启事务的过程中,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程

然后我们new 一个DataSourceTransactionObject了,具体过程如下:

    @Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}

 

  HibernateTransactionManager获取HibernateTransactionObject

  从当前线程中获取绑定的SessionHolder,可能为null,如果为null,则会在下一个开启事务的过程中从sessionFactory中获取一个session,然后封装成SessionHolder,然后再绑定到当前线程

然后我们就可以new 一个HibernateTransactionObject了,具体过程如下:

    @Override
protected Object doGetTransaction() {
HibernateTransactionObject txObject = new HibernateTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed()); SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Hibernate transaction");
}
txObject.setSessionHolder(sessionHolder);
}
else if (this.hibernateManagedSession) {
try {
Session session = this.sessionFactory.getCurrentSession();
if (logger.isDebugEnabled()) {
logger.debug("Found Hibernate-managed Session [" + session + "] for Spring-managed transaction");
}
txObject.setExistingSession(session);
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException(
"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
}
} if (getDataSource() != null) {
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(getDataSource());
txObject.setConnectionHolder(conHolder);
} return txObject;
}

  2. 构建DefaultTransactionStatus,使用Object transaction开启事务

  

  DataSourceTransactionManager的DataSourceTransactionObject开启过程如下:

  首先判断之前的获取当前线程绑定的ConnectionHolder是否为null,如果为null,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程因为开启了一个事务,则必须要关闭DataSourceTransactionObject中Connection的自动提交

    @Override
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()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.dataSource);
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}

  HibernateTransactionManager的HibernateTransactionObject开启过程如下:

也是同样的逻辑,如果SessionHolder为null,则从SessionFactory中获取一个Session,然后封装成SessionHolder,然后把这个SessionHolder绑定到当前线程

  3. 第二个接口:void rollback(TransactionStatus status) 回滚事务

  回滚,则还是利用DefaultTransactionStatus内部的Object transaction来执行回滚操作

  DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection来进行回滚操作

    @Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}

  

  HibernateTransactionManager就是使用HibernateTransactionObject中的SessionHolder中的Session创建的事务Transaction来进行回滚操作

    @Override
protected void doRollback(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Rolling back Hibernate transaction on Session [" +
txObject.getSessionHolder().getSession() + "]");
}
try {
txObject.getSessionHolder().getTransaction().rollback();
}
catch (org.hibernate.TransactionException ex) {
throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
}
catch (HibernateException ex) {
// Shouldn't really happen, as a rollback doesn't cause a flush.
throw convertHibernateAccessException(ex);
}
finally {
if (!txObject.isNewSession() && !this.hibernateManagedSession) {
// Clear all pending inserts/updates/deletes in the Session.
// Necessary for pre-bound Sessions, to avoid inconsistent state.
txObject.getSessionHolder().getSession().clear();
}
}
}

  4.第三个接口: void commit(TransactionStatus status) 提交事务

  同理,DataSourceTransactionManager依托内部的Connection来完成提交操作

  HibernateTransactionManager依托内部的Transaction来完成提交操作

spring---transaction(3)---源代码分析(事务的管理器PlatformTransactionManager)的更多相关文章

  1. spring transaction源码分析--事务架构

    1. 引言  事务特性 事务是并发控制的单元,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性.事 ...

  2. spring---transaction(1)---源代码分析(事务的拦截器TransactionInterceptor)

    写在前面: 先了解一下spring的事务.分为分明式事务管理和注解式事务管理,对于前期的事务,spring会通过扫描拦截对于事务的方法进行增强(以后讲解). 若果目标方法存在事务,spring产出的b ...

  3. TestNG源代码分析:依赖管理的实现

    TestNG源代码分析:依赖管理的实现 2018-03-19 1 背景 当case之间有依赖关系,有依赖关系的case,它们的执行顺序是有限制的.TestNG提供了依赖管理功能 2 基础理论 这个执行 ...

  4. SDL2源代码分析3:渲染器(SDL_Renderer)

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  5. XBMC源代码分析 7:视频播放器(dvdplayer)-输入流(以libRTMP为例)

    前文分析了XBMC的基本结构: XBMC源代码分析 1:整体结构以及编译方法 XBMC源代码分析 2:Addons(皮肤Skin) XBMC源代码分析 3:核心部分(core)-综述 XBMC源代码分 ...

  6. XBMC源代码分析 6:视频播放器(dvdplayer)-文件头(以ffmpeg为例)

    XBMC分析系列文章: XBMC源代码分析 1:整体结构以及编译方法 XBMC源代码分析 2:Addons(皮肤Skin) XBMC源代码分析 3:核心部分(core)-综述 XBMC源代码分析 4: ...

  7. spring---transaction(4)---源代码分析(事务的状态TransactionStatus)

    写在前面 TransactionStatus表示一个具体的事务状态(这里应用到了Java的一个多继承,接口允许多继承) TransactionStatus它继承了SavepointManager接口, ...

  8. redis 源代码分析(一) 内存管理

    一,redis内存管理介绍 redis是一个基于内存的key-value的数据库,其内存管理是很重要的,为了屏蔽不同平台之间的差异,以及统计内存占用量等,redis对内存分配函数进行了一层封装,程序中 ...

  9. spring---transaction(2)---源代码分析(事务的定义TransactionDefinition)

    写在前面 事务属性通过TransactionDefinition接口实现定义,主要有事务隔离级别.事务传播行为.事务超时时间.事务是否只读. public interface TransactionD ...

随机推荐

  1. 转载:Github项目解析(七)-->防止按钮重复点击

    不错的东西,记录下... http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/qq_23547831/article/deta ...

  2. 10 The Go Programming Language Specification go语言规范 重点

    The Go Programming Language Specification go语言规范 Version of May 9, 2018 Introduction 介绍 Notation 符号 ...

  3. 基于RESTful API 设计用户权限控制

    RESTful简述 本文是基于RESTful描述的,需要你对这个有初步的了解. RESTful是什么? Representational State Transfer,简称REST,是Roy Fiel ...

  4. CCF CSP 201703-5 引水入城(50分)

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201703-5 引水入城 问题描述 MF城建立在一片高原上.由于城市唯一的水源是位于河谷地带的 ...

  5. Singleton 多线程

    单例模式 何为单例模式,在GOF的<设计模式:可复用面向对象软件的基础>中是这样说的:保证一个类只有一个实例,并提供一个访问它的全局访问点.首先,需要保证一个类只有一个实例:在类中,要构造 ...

  6. 在Ubuntu 16.04 安装python3.6 环境并设置为默认

    在Ubuntu 16.04 安装python3.6 环境并设置为默认 1.添加python3.6安装包,并且安装 sudo apt-get install software-properties-co ...

  7. bzoj 1233

    先要了解一个结论,在多种可行的堆叠方案中,至少有一种能使层数最高的方案同时使得底边最短.即底边最短的,层数一定最高. dp[ i ] = min(sum[j - 1] - sum[i - 1])  j ...

  8. 如何让 C++ 和 C# 一样易用,而且效率更高?

    (未完成,待续..) 第一章:C++基本功 1. 养成良好的编码习惯. 2. 堆上的资源随用随还,严格控制生命周期. 第二章:一些调试心得 1. 在VisualStudio环境下,曾出现 Detect ...

  9. Ionic Js十五:对话框

    $ionicPopup ionic 对话框服务允许程序创建.显示弹出窗口. $ionicPopup 提供了3个方法:alert(), prompt(),以及 confirm() . 实例 HTML 代 ...

  10. PHP中双引号引起的命令执行漏洞

    前言 在PHP语言中,单引号和双引号都可以表示一个字符串,但是对于双引号来说,可能会对引号内的内容进行二次解释,这就可能会出现安全问题. 正文 举个简单例子 <?php $a = 1; $b = ...