找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1698

积分

0

好友

226

主题
发表于 13 小时前 | 查看: 4| 回复: 0

很多人都会使用 @Transactional 注解,但对于其背后的运行机制,能清晰回答以下问题的人却不多:

  • @Transactional 是怎么被拦截的?
  • 事务什么时候创建?数据库连接又是在哪一步获取的?
  • 为什么在同一个事务内,MyBatis 或 JdbcTemplate 总能拿到同一条 Connection?
  • 最终的回滚和提交操作,究竟是谁来执行的?
  • 关键的 ThreadLocal 又在哪个环节发挥了作用?

这篇文章不会重复讲解 API 如何使用,而是带你深入源码,完整走一遍 @Transactional 的生命周期,看清它究竟是如何“跑”起来的。

@Transactional 并非“魔法”,本质是 AOP

首先需要明确,Spring 的事务管理能力并非 JVM 或 JDBC 层自带的,而是 AOP(面向切面编程)与事务管理器协同工作的结果

整个流程的核心入口只有一个:

TransactionInterceptor

一、TransactionInterceptor 拦截执行

所有被 @Transactional 注解标记的方法调用,最终都会由 TransactionInterceptor 这个 AOP 增强拦截器进行处理。

// 位置:org.springframework.transaction.interceptor.TransactionInterceptor
public class TransactionInterceptor extends TransactionAspectSupport
        implements MethodInterceptor, Serializable {

    @Override
    @Nullable
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 获取目标类
        Class<?> targetClass = (invocation.getThis() != null ?
                AopUtils.getTargetClass(invocation.getThis()) : null);

        // ⭐ 调用父类的事务处理方法
        return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
            @Override
            @Nullable
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();  // 执行目标方法
            }
        });
    }
}

可以看到,它直接调用了父类 TransactionAspectSupportinvokeWithinTransaction 方法,这是整个事务处理逻辑的起点。

二、事务核心处理逻辑

真正的“魔法”发生在 TransactionAspectSupport.invokeWithinTransaction() 方法中。这个方法定义了事务处理的骨架。

// 位置:org.springframework.transaction.interceptor.TransactionAspectSupport
// 这是整个事务处理的核心方法,约在第 340 行
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {

    // ========== 第一步:获取事务属性 ==========
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // 解析 @Transactional 注解的属性(传播行为、隔离级别、超时等)
    final TransactionAttribute txAttr = (tas != null ?
            tas.getTransactionAttribute(method, targetClass) : null);

    // ========== 第二步:确定事务管理器 ==========
    final TransactionManager tm = determineTransactionManager(txAttr);

    // 响应式事务处理(WebFlux)
    if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager rtm) {
        // ... 响应式处理逻辑
    }

    // ========== 第三步:转换为 PlatformTransactionManager ==========
    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager cpptm)) {
        // ========== 第四步:创建事务 ==========
        // ⭐⭐⭐ 这里开始创建/获取事务,并绑定 DataSource 到 ThreadLocal
        TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

        Object retVal;
        try {
            // ========== 第五步:执行目标业务方法 ==========
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // ========== 第六步:异常回滚 ==========
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            // ========== 第七步:清理事务信息 ==========
            cleanupTransactionInfo(txInfo);
        }

        if (retVal != null && txAttr != null) {
            // 处理 Vavr Try 返回值
            // ...
        }

        // ========== 第八步:提交事务 ==========
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }
    else {
        // CallbackPreferringPlatformTransactionManager 处理
        // ...
    }
}

这个骨架清晰地勾勒出了事务的八大步骤。接下来,我们深入几个关键环节。

2.1 确定事务管理器 (determineTransactionManager)

事务管理器 (PlatformTransactionManager) 是执行具体事务操作(如获取连接、提交、回滚)的实体。Spring 通过 determineTransactionManager 方法来确定使用哪一个。

protected TransactionManager determineTransactionManager(
        @Nullable TransactionAttribute txAttr, @Nullable Class<?> targetClass) {

    // ==================== 第一步:尝试从事务属性中获取 ====================
    // 调用已废弃的重载方法,用于向后兼容
    // 如果 @Transactional(transactionManager = "xxx") 指定了事务管理器名称,会在这里处理
    TransactionManager tm = determineTransactionManager(txAttr);
    if (tm != null) {
        return tm;
    }

    // ==================== 第二步:检查前置条件 ====================
    // 如果没有事务属性或没有 BeanFactory,直接返回默认事务管理器
    // 这种情况通常发生在非事务方法或手动配置场景
    if (txAttr == null || this.beanFactory == null) {
        return getTransactionManager();  // 返回通过 setter 注入的默认事务管理器
    }

    // ==================== 第三步:通过 qualifier 限定符查找 ====================
    // 获取 @Transactional 注解中的 qualifier 属性
    // 例如: @Transactional(value = "order") 或 @Transactional("order")
    String qualifier = txAttr.getQualifier();
    if (StringUtils.hasText(qualifier)) {
        // 通过 qualifier 从 BeanFactory 中获取指定的事务管理器
        // 对应的 Bean 需要用 @Qualifier("order") 或 @Bean("order") 标注
        return determineQualifiedTransactionManager(this.beanFactory, qualifier);
    }
    // ==================== 第四步:检查目标类上的 @Qualifier 注解 ====================
    else if (targetClass != null) {
        // 查找目标类上是否有 @Qualifier 注解
        // 例如: @Qualifier("order") @Service public class OrderService { ... }
        String typeQualifier = BeanFactoryAnnotationUtils.getQualifierValue(targetClass);
        if (StringUtils.hasText(typeQualifier)) {
            try {
                return determineQualifiedTransactionManager(this.beanFactory, typeQualifier);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // 类级别的 qualifier 是可选的,找不到时继续往下查找
                // 不抛出异常,而是使用常规解析逻辑
            }
        }
    }

    // ==================== 第五步:通过配置的 Bean 名称查找 ====================
    // 检查是否通过 setTransactionManagerBeanName() 设置了事务管理器的 Bean 名称
    if (StringUtils.hasText(this.transactionManagerBeanName)) {
        return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
    }
    // ==================== 第六步:获取默认事务管理器(兜底逻辑) ====================
    else {
        // 首先尝试获取通过 setter 直接注入的事务管理器
        TransactionManager defaultTransactionManager = getTransactionManager();

        if (defaultTransactionManager == null) {
            // 尝试从缓存中获取(避免重复查找)
            defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);

            if (defaultTransactionManager == null) {
                // ⭐⭐⭐ 核心:从 Spring 容器中按类型获取 TransactionManager
                // 这里会获取到 Spring Boot 自动配置的 JdbcTransactionManager
                // JdbcTransactionManager 是在 DataSourceTransactionManagerAutoConfiguration 中创建的
                // 它持有 HikariDataSource 的引用
                defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);

                // 放入缓存,下次直接使用
                this.transactionManagerCache.putIfAbsent(
                        DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
            }
        }
        return defaultTransactionManager;
    }
}

在 Spring Boot 默认的单数据源场景下,最终会通过 this.beanFactory.getBean(TransactionManager.class) 拿到容器中唯一的 JdbcTransactionManager

Spring Boot 启动
 ↓
DataSourceAutoConfiguration
 ↓ 创建 HikariDataSource 并注入容器
 ↓
DataSourceTransactionManagerAutoConfiguration
 ↓ @ConditionalOnSingleCandidate(DataSource.class) → 检测到 HikariDataSource
 ↓ @ConditionalOnMissingBean(TransactionManager.class) → 没有自定义事务管理器
 ↓
JdbcTransactionManagerConfiguration.transactionManager()
 ↓ 检查 spring.dao.exceptiontranslation.enabled (默认 true)
 ↓
new JdbcTransactionManager(dataSource) ⭐ 创建并注入容器
 ↓
 ↓ 注册 Bean 名称为 "transactionManager"
 ↓
TransactionAspectSupport.determineTransactionManager()
 ↓ this.beanFactory.getBean(TransactionManager.class)
 ↓
返回 JdbcTransactionManager 实例

其自动配置源码如下:

// 位置:org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
// Spring Boot 3.x 源码
@AutoConfiguration(after = { DataSourceAutoConfiguration.class })
@ConditionalOnClass({ JdbcTemplate.class, TransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnSingleCandidate(DataSource.class)  // 存在唯一 DataSource 时生效
    static class JdbcTransactionManagerConfiguration {

        @Bean
        @ConditionalOnMissingBean(TransactionManager.class)  // 没有自定义事务管理器时才创建
        // ⭐⭐⭐ 这里创建的就是 JdbcTransactionManager(Spring Boot 3.x)
        // 而不是 DataSourceTransactionManager
        DataSourceTransactionManager transactionManager(
                Environment environment,
                DataSource dataSource,  // 注入 HikariDataSource
                ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {

            // ⭐ 关键:createTransactionManager 方法
            DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
            transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
            return transactionManager;
        }

        private DataSourceTransactionManager createTransactionManager(Environment environment, DataSource dataSource) {
            return environment.getProperty("spring.dao.exceptiontranslation.enabled", Boolean.class, Boolean.TRUE)
                    ? new JdbcTransactionManager(dataSource) : new DataSourceTransactionManager(dataSource);
        }

    }

}

2.2 createTransactionIfNecessary() - 创建事务

确定事务管理器后,便调用 createTransactionIfNecessary 来准备事务。

// 位置:TransactionAspectSupport 第 620 行左右
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
        @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

    // 包装事务属性
    if (txAttr != null && txAttr.getName() == null) {
        txAttr = new DelegatingTransactionAttribute(txAttr) {
            @Override
            public String getName() {
                return joinpointIdentification;
            }
        };
    }

    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            // ⭐⭐⭐ 核心:调用事务管理器获取事务
            status = tm.getTransaction(txAttr);
        }
    }

    // 准备事务信息并绑定到当前线程
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

这里的关键是 tm.getTransaction(txAttr),它委托给具体的事务管理器来开启或加入一个事务。

三、事务管理器获取/创建事务(DataSource 绑定的关键)

3.1 getTransaction

AbstractPlatformTransactionManager.getTransaction() 是事务获取的模板方法,处理了事务传播行为等核心逻辑。

// 位置:org.springframework.transaction.support.AbstractPlatformTransactionManager
// 约在第 370 行
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
        throws TransactionException {

    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

    // ⭐ 第一步:获取当前事务对象(检查是否已有事务)
    Object transaction = doGetTransaction();  // 由子类 DataSourceTransactionManager 实现

    boolean debugEnabled = logger.isDebugEnabled();

    // ⭐ 第二步:检查是否已存在事务
    if (isExistingTransaction(transaction)) {
        // 根据传播行为处理已存在的事务
        return handleExistingTransaction(def, transaction, debugEnabled);
    }

    // ========== 以下是不存在事务的情况 ==========

    // 检查超时
    if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    }

    // MANDATORY:必须在事务中运行,否则抛异常
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException(
                "No existing transaction found for transaction marked with propagation 'mandatory'");
    }
    // REQUIRED、REQUIRES_NEW、NESTED:需要开启新事务
    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

        // 挂起当前资源(如果有)
        SuspendedResourcesHolder suspendedResources = suspend(null);

        try {
            // ⭐⭐⭐ 开启新事务
            return startTransaction(def, transaction, debugEnabled, suspendedResources);
        }
        catch (RuntimeException | Error ex) {
            resume(null, suspendedResources);
            throw ex;
        }
    }
    else {
        // SUPPORTS、NOT_SUPPORTED、NEVER:创建“空”事务
        if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
            logger.warn("Custom isolation level specified but no actual transaction initiated...");
        }
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    }
}

3.2 startTransaction() - 开启新事务

对于需要新事务的情况,会进入 startTransaction 方法。

// 位置:AbstractPlatformTransactionManager 约第 400 行
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
        boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

    // 创建事务状态对象
    DefaultTransactionStatus status = newTransactionStatus(
            definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

    // ⭐⭐⭐ 核心:真正开始事务(由子类实现)
    doBegin(transaction, definition);

    // 准备事务同步(初始化 TransactionSynchronizationManager)
    prepareSynchronization(status, definition);

    return status;
}

doBegin(transaction, definition) 是一个抽象方法,由具体的事务管理器实现。对于 JDBC 事务,就是 DataSourceTransactionManager.doBegin()。这里也是数据库连接获取和绑定的核心。

3.3 DataSourceTransactionManager.doGetTransaction() - 获取事务对象

在判断是否存在事务时,会调用 doGetTransaction()

// 位置:org.springframework.jdbc.datasource.DataSourceTransactionManager
// 约第 220 行
@Override
protected Object doGetTransaction() {
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed());

    // ⭐⭐⭐ 关键:从 TransactionSynchronizationManager 获取当前线程绑定的 ConnectionHolder
    // 如果之前已经在事务中,这里会获取到已有的连接
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
            .getResource(obtainDataSource());  // obtainDataSource() 返回 HikariDataSource

    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

这个方法第一次揭示了 TransactionSynchronizationManager 的作用:它像一个注册中心,存储着当前线程与事务相关的资源(如数据库连接)。

3.4 DataSourceTransactionManager.doBegin() - 真正开启事务 (DataSource 绑定时机)

这是整个流程中最关键的方法之一,数据库连接的获取、事务的开启(关闭自动提交)、以及资源与线程的绑定都在这里发生。

// 位置:DataSourceTransactionManager 约第 260 行
// ⭐⭐⭐ 这是 DataSource 绑定到 TransactionSynchronizationManager 的关键方法
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;

    try {
        // ========== 第一步:获取数据库连接 ==========
        if (!txObject.hasConnectionHolder() ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {

            // ⭐⭐⭐ 从 DataSource(HikariDataSource)获取新连接
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            // 创建新的 ConnectionHolder 并标记为新连接
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }

        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        con = txObject.getConnectionHolder().getConnection();

        // ========== 第二步:准备连接(设置隔离级别、只读等) ==========
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);
        txObject.setReadOnly(definition.isReadOnly());

        // ========== 第三步:关闭自动提交(开启事务的本质) ==========
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            // ⭐⭐⭐ JDBC 层面开启事务的本质:关闭自动提交
            con.setAutoCommit(false);
        }

        // 准备事务连接(设置只读等)
        prepareTransactionalConnection(con, definition);

        // 标记事务为活跃状态
        txObject.getConnectionHolder().setTransactionActive(true);

        // ========== 第四步:设置超时 ==========
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }

        // ========== ⭐⭐⭐ 第五步:绑定 DataSource 和 ConnectionHolder 到 TransactionSynchronizationManager ==========
        if (txObject.isNewConnectionHolder()) {
            // 这是关键!!!将 DataSource -> ConnectionHolder 的映射绑定到当前线程
            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);
    }
}

核心点:在第5步,通过 TransactionSynchronizationManager.bindResource(),将 DataSource 和代表数据库连接的 ConnectionHolder 绑定到了当前线程。这保证了后续在同一个线程内,任何需要数据库连接的地方,都能通过同一个 DataSource 键获取到这个特定的连接。

四、TransactionSynchronizationManager - 线程绑定管理

4.1 资源绑定核心实现

TransactionSynchronizationManager 是 Spring 事务同步管理的核心工具类,它内部使用 ThreadLocal 来保存线程隔离的事务资源。

// 位置:org.springframework.transaction.support.TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager {

    // ⭐⭐⭐ 核心:使用 ThreadLocal 存储资源(DataSource -> ConnectionHolder)
    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<>("Transactional resources");

    // 事务同步器列表
    private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
            new NamedThreadLocal<>("Transaction synchronizations");

    // 当前事务名称
    private static final ThreadLocal<String> currentTransactionName =
            new NamedThreadLocal<>("Current transaction name");

    // 当前事务只读标志
    private static final ThreadLocal<Boolean> currentTransactionReadOnly =
            new NamedThreadLocal<>("Current transaction read-only status");

    // 当前事务隔离级别
    private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
            new NamedThreadLocal<>("Current transaction isolation level");

    // 事务是否激活
    private static final ThreadLocal<Boolean> actualTransactionActive =
            new NamedThreadLocal<>("Actual transaction active");

    // ========== 资源绑定方法 ==========

    /**
     * ⭐⭐⭐ 绑定资源到当前线程
     * 在 DataSourceTransactionManager.doBegin() 中调用
     * key = HikariDataSource, value = ConnectionHolder
     */
    public static void bindResource(Object key, Object value) throws IllegalStateException {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        Assert.notNull(value, "Value must not be null");

        Map<Object, Object> map = resources.get();
        if (map == null) {
            map = new HashMap<>();
            resources.set(map);
        }

        Object oldValue = map.put(actualKey, value);
        if (oldValue instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
            oldValue = null;
        }
        if (oldValue != null) {
            throw new IllegalStateException(
                    "Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread");
        }
    }

    /**
     * ⭐⭐⭐ 获取当前线程绑定的资源
     * MyBatis/JdbcTemplate 获取连接时会调用此方法
     */
    @Nullable
    public static Object getResource(Object key) {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        return doGetResource(actualKey);
    }

    @Nullable
    private static Object doGetResource(Object actualKey) {
        Map<Object, Object> map = resources.get();
        if (map == null) {
            return null;
        }
        Object value = map.get(actualKey);
        if (value instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
            map.remove(actualKey);
            if (map.isEmpty()) {
                resources.remove();
            }
            value = null;
        }
        return value;
    }

    /**
     * 解绑资源(事务结束时调用)
     */
    public static Object unbindResource(Object key) throws IllegalStateException {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        Object value = doUnbindResource(actualKey);
        if (value == null) {
            throw new IllegalStateException("No value for key [" + actualKey + "] bound to thread");
        }
        return value;
    }
}

正是通过这个 ThreadLocal<Map> 结构,Spring 实现了事务资源(尤其是数据库连接)的线程绑定,这是保证同一事务内操作使用同一连接的核心机制。理解这个机制,对于处理复杂的并发和连接池问题至关重要,更多关于 Java 并发与资源管理的深入探讨,可以在相关社区找到。

五、MyBatis 如何获取事务中的连接

当业务方法中通过 MyBatis 执行 SQL 时,它是如何拿到那个被绑定到当前线程的 Connection 的呢?

5.1 SpringManagedTransaction(MyBatis-Spring)

MyBatis-Spring 整合包提供了一个 SpringManagedTransaction,它替代了 MyBatis 默认的事务管理。

// 位置:org.mybatis.spring.transaction.SpringManagedTransaction
public class SpringManagedTransaction implements Transaction {

    private final DataSource dataSource;
    private Connection connection;
    private boolean isConnectionTransactional;
    private boolean autoCommit;

    public SpringManagedTransaction(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Connection getConnection() throws SQLException {
        if (this.connection == null) {
            openConnection();
        }
        return this.connection;
    }

    private void openConnection() throws SQLException {
        // ⭐⭐⭐ 关键:通过 DataSourceUtils 获取连接
        // 如果当前线程在事务中,会返回 TransactionSynchronizationManager 中绑定的连接
        this.connection = DataSourceUtils.getConnection(this.dataSource);
        this.autoCommit = this.connection.getAutoCommit();
        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
    }

    @Override
    public void commit() throws SQLException {
        // 如果连接是事务管理的,不在这里提交(由 Spring 事务管理器提交)
        if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
            this.connection.commit();
        }
    }

    @Override
    public void rollback() throws SQLException {
        // 同上,由 Spring 事务管理器回滚
        if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
            this.connection.rollback();
        }
    }
}

可以看到,它把获取连接的工作委托给了 Spring 的 DataSourceUtils.getConnection()

5.2 DataSourceUtils.getConnection() - 获取连接的核心

这是连接获取的统一门户,无论是 MyBatis 还是 JdbcTemplate,最终都会走到这里。

// 位置:org.springframework.jdbc.datasource.DataSourceUtils
public abstract class DataSourceUtils {

    /**
     * ⭐⭐⭐ 获取数据库连接
     * 如果当前线程在事务中,返回事务绑定的连接
     * 否则从 DataSource 获取新连接
     */
    public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
        try {
            return doGetConnection(dataSource);
        }
        catch (SQLException ex) {
            throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
        }
        catch (IllegalStateException ex) {
            throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
        }
    }

    public static Connection doGetConnection(DataSource dataSource) throws SQLException {
        Assert.notNull(dataSource, "No DataSource specified");

        // ⭐⭐⭐ 关键:从 TransactionSynchronizationManager 获取当前线程绑定的 ConnectionHolder
        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

        // 如果存在绑定的连接,直接返回(保证事务中使用同一个连接)
        if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
            conHolder.requested();
            if (!conHolder.hasConnection()) {
                conHolder.setConnection(fetchConnection(dataSource));
            }
            return conHolder.getConnection();  // ⭐ 返回事务中的连接
        }

        // 没有绑定连接,从 DataSource 获取新连接
        Connection con = fetchConnection(dataSource);

        // 如果当前有事务同步激活,注册同步器
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            // ...
        }

        return con;
    }
}

逻辑非常清晰:首先尝试从 TransactionSynchronizationManager 中获取当前线程绑定的 ConnectionHolder。如果存在(说明当前正在事务中),则直接返回其中的 Connection;如果不存在,才从数据源获取一个新的连接。这就完美解释了为何事务内的数据库操作总是使用同一个连接。

六、事务提交与回滚

业务方法执行完毕后,根据是否发生异常,决定是提交还是回滚。

6.1 提交事务

// 位置:TransactionAspectSupport
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

// 位置:AbstractPlatformTransactionManager
@Override
public final void commit(TransactionStatus status) throws TransactionException {
    // ...
    processCommit(defStatus);
}

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    try {
        // 触发 beforeCommit 回调
        triggerBeforeCommit(status);
        // 触发 beforeCompletion 回调
        triggerBeforeCompletion(status);

        if (status.isNewTransaction()) {
            // ⭐ 真正提交事务
            doCommit(status);
        }
        // ...
    }
    finally {
        cleanupAfterCompletion(status);
    }
}

// 位置:DataSourceTransactionManager
@Override
protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        // ⭐⭐⭐ JDBC 提交
        con.commit();
    }
    catch (SQLException ex) {
        throw translateException("JDBC commit", ex);
    }
}

6.2 回滚事务

// 位置:TransactionAspectSupport
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // 判断是否需要回滚(默认只回滚 RuntimeException 和 Error)
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
        }
        else {
            // 不回滚,正常提交
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
    }
}

// 位置:DataSourceTransactionManager
@Override
protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        // ⭐⭐⭐ JDBC 回滚
        con.rollback();
    }
    catch (SQLException ex) {
        throw translateException("JDBC rollback", ex);
    }
}

6.3 清理资源

无论提交还是回滚,最后都必须清理资源,将连接归还给连接池,并解除线程绑定。

// 位置:AbstractPlatformTransactionManager
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    status.setCompleted();

    if (status.isNewSynchronization()) {
        // 清理 TransactionSynchronizationManager
        TransactionSynchronizationManager.clear();
    }

    if (status.isNewTransaction()) {
        // ⭐ 清理事务资源
        doCleanupAfterCompletion(status.getTransaction());
    }

    if (status.getSuspendedResources() != null) {
        // 恢复挂起的事务
        resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
    }
}

// 位置:DataSourceTransactionManager
@Override
protected void doCleanupAfterCompletion(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

    if (txObject.isNewConnectionHolder()) {
        // ⭐⭐⭐ 从 TransactionSynchronizationManager 解绑 DataSource
        TransactionSynchronizationManager.unbindResource(obtainDataSource());
    }

    Connection con = txObject.getConnectionHolder().getConnection();
    try {
        // 恢复自动提交
        if (txObject.isMustRestoreAutoCommit()) {
            con.setAutoCommit(true);
        }
        // 重置连接状态
        DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
    }
    catch (Throwable ex) {
        logger.debug("Could not reset JDBC Connection after transaction", ex);
    }

    if (txObject.isNewConnectionHolder()) {
        // ⭐ 释放连接回连接池
        DataSourceUtils.releaseConnection(con, this.dataSource);
    }

    txObject.getConnectionHolder().clear();
}

七、完整流程图总结

最后,我们用一张完整的流程图来串联整个 @Transactional 的执行过程,这有助于你从全局视角理解 Spring 事务管理的 AOP 设计思想。

┌─────────────────────────────────────────────────────────────────────────────┐
│ @Transactional 完整执行流程                                                 │
└─────────────────────────────────────────────────────────────────────────────┘

1. Spring Boot 启动阶段
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ TransactionAutoConfiguration                                             │
 │   └── @EnableTransactionManagement                                      │
 │       └── ProxyTransactionManagementConfiguration                       │
 │           ├── TransactionInterceptor (Bean)                             │
 │           └── BeanFactoryTransactionAttributeSourceAdvisor (Bean)       │
 │                                                                          │
 │ DataSourceTransactionManagerAutoConfiguration                           │
 │   └── DataSourceTransactionManager (Bean)                               │
 │       └── 注入 HikariDataSource                                         │
 └──────────────────────────────────────────────────────────────────────────┘
 ↓
2. Bean 创建阶段(对 @Transactional 标注的类创建代理)
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ AbstractAutoProxyCreator.postProcessAfterInitialization()                │
 │   └── wrapIfNecessary()                                                 │
 │       └── createProxy() → 返回 CGLIB 代理对象                           │
 └──────────────────────────────────────────────────────────────────────────┘
 ↓
3. 方法调用阶段
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ 调用 @Transactional 方法                                                 │
 │     ↓                                                                   │
 │ CglibAopProxy.DynamicAdvisedInterceptor.intercept()                     │
 │     ↓                                                                   │
 │ TransactionInterceptor.invoke()                                         │
 │     ↓                                                                   │
 │ TransactionAspectSupport.invokeWithinTransaction()                      │
 └──────────────────────────────────────────────────────────────────────────┘
 ↓
4. 创建/获取事务
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ TransactionAspectSupport.createTransactionIfNecessary()                 │
 │     ↓                                                                   │
 │ AbstractPlatformTransactionManager.getTransaction()                     │
 │     ├── doGetTransaction() → 检查是否已有事务                           │
 │     └── startTransaction()                                              │
 │         ↓                                                               │
 │ DataSourceTransactionManager.doBegin()                                  │
 │     ├── dataSource.getConnection() → 从 HikariPool 获取连接             │
 │     ├── connection.setAutoCommit(false) → 开启事务                      │
 │     └── TransactionSynchronizationManager.bindResource()                │
 │         ↓                                                               │
 │ ⭐ 将 HikariDataSource -> ConnectionHolder 绑定到 ThreadLocal           │
 └──────────────────────────────────────────────────────────────────────────┘
 ↓
5. 执行业务方法(MyBatis 获取连接)
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ invocation.proceedWithInvocation() → 执行目标方法                       │
 │     ↓                                                                   │
 │ MyBatis Mapper 执行 SQL                                                 │
 │     ↓                                                                   │
 │ SpringManagedTransaction.getConnection()                                │
 │     ↓                                                                   │
 │ DataSourceUtils.getConnection(dataSource)                               │
 │     ↓                                                                   │
 │ TransactionSynchronizationManager.getResource(dataSource)               │
 │     ↓                                                                   │
 │ ⭐ 返回步骤4绑定的 ConnectionHolder 中的 Connection(同一个连接!)     │
 └──────────────────────────────────────────────────────────────────────────┘
 ↓
6. 事务提交或回滚
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ 正常完成:                                                                │
 │   commitTransactionAfterReturning()                                     │
 │     → DataSourceTransactionManager.doCommit()                           │
 │     → connection.commit()                                               │
 │                                                                          │
 │ 异常发生:                                                                │
 │   completeTransactionAfterThrowing()                                    │
 │     → DataSourceTransactionManager.doRollback()                         │
 │     → connection.rollback()                                             │
 └──────────────────────────────────────────────────────────────────────────┘
 ↓
7. 清理资源
 ┌──────────────────────────────────────────────────────────────────────────┐
 │ cleanupAfterCompletion()                                                │
 │     ↓                                                                   │
 │ DataSourceTransactionManager.doCleanupAfterCompletion()                 │
 │     ├── TransactionSynchronizationManager.unbindResource() → 解绑       │
 │     ├── connection.setAutoCommit(true) → 恢复自动提交                   │
 │     └── DataSourceUtils.releaseConnection() → 归还连接到 HikariPool     │
 └──────────────────────────────────────────────────────────────────────────┘

希望通过这篇源码级别的剖析,能让你对 Spring @Transactional 事务的管理机制有一个透彻的理解。从 AOP 拦截,到事务管理器的协调,再到通过 ThreadLocal 实现的线程资源绑定,每一个环节都体现了 Spring 框架精妙的设计。掌握这些底层原理,将帮助你更好地使用和调试基于 数据库/中间件 的 Spring 事务,写出更健壮的应用。如果你想与其他开发者深入交流这类技术细节,欢迎到 云栈社区 参与讨论。




上一篇:传音MWC 2026前瞻:超薄模块化与副屏交互新机解析
下一篇:手写Mybatis第一步:深度解析JDK动态代理原理与实战
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-28 22:14 , Processed in 0.604584 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表