Spring5源码(45)-@Transactional声明式事物(三)事物创建

简介: Spring5源码(45)-@Transactional声明式事物(三)事物创建


1.引

上一节已经分析了了在单service单方法下的事物创建过程以及其后续处理工作,当然还缺少真正创建事物的分析,本篇接续。先来回顾一下事物创建的代码片段:

try {
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // 创建DefaultTransactionStatus对象实例
    DefaultTransactionStatus status = newTransactionStatus(
            definition,
            transaction,
            true,
            newSynchronization,
            debugEnabled,
            suspendedResources);
    // 开启事物
    doBegin(transaction, definition);
    // 初始化事务同步。
    prepareSynchronization(status, definition);
    return status;
}
2.创建DefaultTransactionStatus对象

/**
 * 创建DefaultTransactionStatus实例
 * Create a TransactionStatus instance for the given arguments.
 */
protected DefaultTransactionStatus newTransactionStatus(
        TransactionDefinition definition,
        @Nullable Object transaction,
        boolean newTransaction,
        boolean newSynchronization,
        boolean debug,
        @Nullable Object suspendedResources) {
    boolean actualNewSynchronization = newSynchronization && !TransactionSynchronizationManager.isSynchronizationActive();
    return new DefaultTransactionStatus(
            transaction,
            newTransaction,
            actualNewSynchronization,
            definition.isReadOnly(),
            debug,
            suspendedResources);
}
//构造方法
public DefaultTransactionStatus(
            @Nullable Object transaction,
            boolean newTransaction,
            boolean newSynchronization,
            boolean readOnly,
            boolean debug,
            @Nullable Object suspendedResources) {
    this.transaction = transaction;
    this.newTransaction = newTransaction;
    this.newSynchronization = newSynchronization;
    this.readOnly = readOnly;
    this.debug = debug;
    this.suspendedResources = suspendedResources;
}
3.开启事物

针对不同的事物管理器会有不同的事物开启过程,本例我们只看DataSourceTransactionManager下的事物开启过程:

protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;
    try {
        // ConnectionHolder简介:包装JDBC连接的资源容器。DataSourceTransactionManager将该类的实例绑定到特定数据源的线程。
        // 如果txObject没有ConnectionHolder或者connectionHolder并没有加同步锁,则为其设置ConnectionHolder并加同步锁
        if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // 从数据源获取连接
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            // 设置DataSourceTransactionObject的ConnectionHolder对象
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }
        // 设置同步锁标记
        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        // 从ConnectionHolder对象中获取连接
        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).
        // 如果需要,切换到手动提交。
        // 在某些JDBC驱动程序中,这是非常昂贵的,所以我们不想做不必要的事情
        // (例如,如果我们已经显式地配置了连接池来设置它)。
        // 所以:如果连接设置了自动提交,这里要将其转换为手动提交
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false);
        }
        // 设置当前事物只读,如果定义了只读属性为true
        prepareTransactionalConnection(con, definition);
        // 设置当前事物为已激活
        txObject.getConnectionHolder().setTransactionActive(true);
        // 设置超时时间(如果超时时间不等于默认超时时间)
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }
        // Bind the connection holder to the thread.
        // 绑定ConnectionHolder到当前线程
        if (txObject.isNewConnectionHolder()) {
            // 即TransactionSynchronizationManager类的resources对象:
            // 该对象保存每个事物线程对应的connection或session等类型的资源
            // private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }
    // 异常处理
    catch (Throwable ex) {
        if (txObject.isNewConnectionHolder()) {
            DataSourceUtils.releaseConnection(con, obtainDataSource());
            txObject.setConnectionHolder(null, false);
        }
        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
    }
}

该方法也比较简单,相信大家都能看懂,其中关于ConnectionHolder(前文没有讲解)对象,也已经在注释里做过介绍了。

4.初始化事物同步

/**
 * 根据需要初始化事务同步。
 * Initialize transaction synchronization as appropriate.
 */
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
    if (status.isNewSynchronization()) {
        // 设置事物激活状态
        TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
        // 设置事物隔离级别
        TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ? definition.getIsolationLevel() : null);
        // 设置事物只读属性
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        // 设置事物名称
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        // 激活当前线程的事务同步。事务管理器在事务开始时调用。
        TransactionSynchronizationManager.initSynchronization();
    }
}

总体来讲上面的内容还是比较简单的,不做过多的分析了。

5.其他事物特性处理

以上分析的都是基于单service下单个方法调用的事物创建过程,且当前不存在事物,那么对于其它的事物的特性呢?接下来就分析一下其他的特性,其实前面的章节已经有过简单的介绍了,这里再详细分析下。对于PROPAGATION_NESTED特性会直接抛出异常。

那么下面介绍一下PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER特性事物处理过程,先来看一下代码片段:

// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
    logger.warn("Custom isolation level specified but no actual transaction initiated; "
            + "isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
        definition,
        null,
        true,
        newSynchronization,
        debugEnabled,
        null);

protected final DefaultTransactionStatus prepareTransactionStatus(
        TransactionDefinition definition,
        @Nullable Object transaction,
        boolean newTransaction,
        boolean newSynchronization,
        boolean debug,
        @Nullable Object suspendedResources) {
    DefaultTransactionStatus status = newTransactionStatus(
            definition,
            transaction,
            newTransaction,
            newSynchronization,
            debug,
            suspendedResources);
    prepareSynchronization(status, definition);
    return status;
}

从代码里可以看到,该处理与创建真正的事物的过程相似,只是传递的参数不同罢了。大家可以多设定几种传播特性,跟踪一下代码即可



目录
相关文章
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
1月前
|
Java 数据库 Spring
【spring(四)】Spring事务管理和@Transactional注解
【spring(四)】Spring事务管理和@Transactional注解
|
1月前
|
Java 测试技术 数据库连接
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
|
3天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
10天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
1月前
|
Java Spring
使用spring实现邮件的发送(含测试,源码,注释)
使用spring实现邮件的发送(含测试,源码,注释)
7 0
|
1月前
|
Java Spring 容器
【Spring源码】单例创建期间进行同步可能会导致死锁?
通过这个标题我们就可以思考本次的阅读线索了,看起来可以学到不少东西。1. 旧代码的死锁是怎么产生的。2. 贡献者通过改变什么来解决本次PR的问题呢?而阅读线索2的答案也显而易见,就是上文提到的通过后台线程来创建Micrometer单例...
42 3
|
1月前
|
XML Java 开发者
【Spring源码解读 底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理讲解
【Spring源码解读 底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理讲解
|
30天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
44 0
|
1月前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
113 0