转载。 https://blog.csdn.net/qpfjalzm123/article/details/83717367

本文只是对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事务传播实现源码分析的更多相关文章

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

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

  2. Spring JPA实现逻辑源码分析总结

    1.SharedEntityManagerCreator: entitymanager的创建入口 该类被EntityManagerBeanDefinitionRegistrarPostProcesso ...

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

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

  4. spring boot 2.0 源码分析(一)

    在学习spring boot 2.0源码之前,我们先利用spring initializr快速地创建一个基本的简单的示例: 1.先从创建示例中的main函数开始读起: package com.exam ...

  5. spring boot 2.0 源码分析(四)

    在上一章的源码分析里,我们知道了spring boot 2.0中的环境是如何区分普通环境和web环境的,以及如何准备运行时环境和应用上下文的,今天我们继续分析一下run函数接下来又做了那些事情.先把r ...

  6. Spring中Bean命名源码分析

    Spring中Bean命名源码分析 一.案例代码 首先是demo的整体结构 其次是各个部分的代码,代码本身比较简单,不是我们关注的重点 配置类 /** * @Author Helius * @Crea ...

  7. Spring Boot 自动配置 源码分析

    Spring Boot 最大的特点(亮点)就是自动配置 AutoConfiguration 下面,先说一下 @EnableAutoConfiguration ,然后再看源代码,到底自动配置是怎么配置的 ...

  8. Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析

    一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...

  9. Spring基础系列-AOP源码分析

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...

随机推荐

  1. MMU实验

    内存管理单元 MMU介绍:权限管理:地址映射 权限管理:内核->A->B 地址空间各不相同 地址映射:多任务系统也是分时系统 虚拟地址(地址空间)->MMU->物理地址 SDR ...

  2. Emacs的一些事情(与Vi的争议及使用)

    一年成为Emacs高手(像神一样使用编辑器)推荐文章 http://ftp.gnu.org/gnu/emacs/windows/http://blog.csdn.net/redguardtoo/art ...

  3. elixir环境配置

    mac下 brew install elixir debian下版本可能太低,需要kiex 安装 curl -sSL https://raw.githubusercontent.com/taylor/ ...

  4. PHP echo()、print()、print_r()、var_dump()、var_export()的区别

    PHP中echo.print.print_r.var_dump.var_export的用法与区别 这些均为输出变量的内容: echo();不是函数.是PHP语句.没有返回值:输出一个或者多个字符串或者 ...

  5. 玄学曲线并不玄 教你如何看懂GPU呈现

    红色代表了“执行时间”,它指的是Android渲染引擎执行盒子中这些绘制命令的时间,假如当前界面的视图越多,那么红色便会“跳”得越高.实际使用中,比如我们平时刷淘宝App时遇到出现多张缩略图需要加载时 ...

  6. C#多线程更新,查询MongoDB数据

    对多线程一直在用,但是从来没去深入研究过注意的事项,包括和锁的配合也是一知半解没有真正理解锁(lock)的用法. 这次在做数据分析是需要将访问的url中host部分记录,如果已经存在就直接匹配id,没 ...

  7. MySQL数据库解决乱码 latin1 转 gbk

    latin1 也是一种编码,但是有时候它不适合我们正常的使用,所以我需要把它转成gbk编码. 查询数据库编码 show variables like 'character%'; 修改配置文件 my.i ...

  8. Java-Runoob-高级教程-实例-方法:03. Java 实例 – 汉诺塔算法-un

    ylbtech-Java-Runoob-高级教程-实例-方法:03. Java 实例 – 汉诺塔算法 1.返回顶部 1. Java 实例 - 汉诺塔算法  Java 实例 汉诺塔(又称河内塔)问题是源 ...

  9. 父级元素position:absolute,子节点也是absolute

    当父级属性position是absolute,子节点也是absolute的时候,子节点是相对父级absolute的,举个例子 <div class="headManage"& ...

  10. centos7图形化界面安装后,意外出现Please make your choice from above ['q' to quit | 'c' to continue | 'r' to refresh]

    安装完成centos7-GUI后出现如下提示: nitial setup of CentOS Linux (core) ) [x] Creat user ) [!] License informati ...