Spring 源码探险:事务管理的终极奥义——@Transactional 背后的深水区

@Transactional,它可能是我们代码库中最常见、也最能给我们带来“安全感”的注解。我们把它标注在 Service 方法上,就仿佛给这段代码上了一道保险。我们坚信,方法内的所有数据库操作,都会被一个原子性的事务包裹。

但这种“信念”,往往是盲目的。

你是否想过:

  • Spring 是如何知道一个方法需要事务的?仅仅因为一个注解吗?
  • 事务是在方法执行的哪个瞬间开启的?又是在哪个瞬间提交或回滚的?
  • Connection 对象是如何在不同 DAO 方法之间传递并保持统一的?
  • RuntimeException 抛出时,回滚是如何被触发的?那 Exception 呢?
  • @Transactionalpropagation(传播行为)和 isolation(隔离级别)这些属性,又是如何影响底层代码执行的?

@Transactional 对我们来说,就像一个最熟悉的陌生人。我们每天与它擦肩而过,却从未真正了解过它的内心。今天,我们的终极任务,就是彻底撬开它的心防,看清它背后那套由 IoC、AOP 和数据库连接共同编织的、复杂而精密的控制逻辑。

第一章:@Transactional 的黎明——它何时生效?

首先要明确一个核心前提:@Transactional 注解本身,不具备任何能力。 它和 @Override 一样,是一个纯粹的元数据“标记”。让这个标记“活”起来的,是我们早已探明的老朋友——Spring AOP

在现代 Spring Boot 应用中,这一切是如何自动发生的?

  1. 自动配置的起点:TransactionAutoConfiguration
  2. 在 Spring Boot 的“藏宝图” (AutoConfiguration.imports) 中,赫然列着 TransactionAutoConfiguration
  3. 这个自动配置类被 @ConditionalOnClass({ PlatformTransactionManager.class }) 守护着。当我们引入 spring-boot-starter-jdbcspring-boot-starter-data-jpa 时,DataSourceTransactionManagerAutoConfiguration 会被激活,它会为我们自动配置一个 DataSourceTransactionManager 的 Bean(它就是 PlatformTransactionManager 的一种实现)。
  4. 这个条件一旦满足,TransactionAutoConfiguration 就会生效。
  5. 开启事务管理:@EnableTransactionManagement
  6. TransactionAutoConfiguration 的主要作用,就是替我们加上了那个在非 Boot 时代需要手动添加的核心注解:@EnableTransactionManagement
  7. 导入核心组件:ProxyTransactionManagementConfiguration
  8. @EnableTransactionManagement 会通过 @Import 导入一个名为 ProxyTransactionManagementConfiguration 的配置类。
  9. 这个配置类,是整个事务 AOP 功能的“兵工厂”。它向 Spring IoC 容器中注册了几个至关重要的 Bean。其中最重要的一个,就是事务 Advisor
  10. 源码路径: org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration {
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
            TransactionAttributeSource transactionAttributeSource,
            TransactionInterceptor transactionInterceptor) {

        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        advisor.setAdvice(transactionInterceptor);
        // ...
        return advisor;
    }
    // ... 还注册了 TransactionAttributeSource 和 TransactionInterceptor
}

看,最终的秘密武器登场了!它是一个 Advisor!结合我们对 AOP 的理解,一切都说得通了:

  • Spring Boot 自动配置了事务 Advisor
  • 这个 Advisor 会在 Bean 初始化时,像所有其他 Advisor 一样,通过 Pointcut 去匹配所有方法。
  • 一旦某个方法被 @Transactional 标注,Pointcut 匹配成功,AOP 就会为这个 Bean 创建一个代理对象。

至此,所有被 @Transactional 标注的方法,都已经处在 AOP 代理的掌控之下了。

第二章:TransactionInterceptor——事务 AOP 的心脏

BeanFactoryTransactionAttributeSourceAdvisor 这个 Advisor 的结构非常经典:

  1. Pointcut (切点): 它内部的 TransactionAttributeSourcePointcut 负责匹配。它会扫描方法,如果方法上或方法所在的类上存在 @Transactional 注解,则匹配成功。
  2. Advice (通知): 这就是 ProxyTransactionManagementConfiguration 中注册的另一个核心 Bean——TransactionInterceptor。它是一个 MethodInterceptor,是真正执行事务逻辑的地方。

当我们调用一个被代理的、带有 @Transactional 注解的方法时,AOP 的调用链机制会启动,最终会执行到 TransactionInterceptorinvoke 方法。

  • 源码路径: org.springframework.transaction.interceptor.TransactionInterceptor#invoke

这个 invoke 方法,就是我们本次探险的“风暴中心”。所有关于事务的开启、提交、回滚、传播行为的复杂逻辑,都封装于此。


第三章:invoke 方法内的风暴——事务的完整生命周期

TransactionInterceptorinvoke 方法,将核心逻辑委托给了父类 TransactionAspectSupport 的一个同名方法。让我们直接进入这个核心。

  • 源码路径: org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
// TransactionAspectSupport.java
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {

    // 1. 获取事务属性 (@Transactional注解中的 propagation, isolation, timeout 等信息)
    TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);

    // 2. 获取 PlatformTransactionManager (例如 DataSourceTransactionManager)
    PlatformTransactionManager ptm = determineTransactionManager(txAttr);

    // ...

    // 3. 开启事务 (最核心的步骤)
    TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

    Object retVal = null;
    try {
        // 4. 执行真正的目标方法 (AOP调用链的 proceed())
        retVal = invocation.proceedWithInvocation();
    }
    catch (Throwable ex) {
        // 5. 如果发生异常,执行回滚
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    }
    finally {
        // 6. 清理事务信息
        cleanupTransactionInfo(txInfo);
    }

    // 7. 如果没有异常,执行提交
    commitTransactionAfterReturning(txInfo);

    return retVal;
}

这段代码就是 @Transactional 的完整生命周期。让我们把它拆解成一部“七步史诗”:

  1. getTransactionAttribute() - 获取事务属性:

  2. 它会解析方法上的 @Transactional 注解,将其所有属性(propagationisolationtimeoutreadOnlyrollbackFor 等)封装成一个 TransactionAttribute 对象。这是后续所有决策的依据。

  3. determineTransactionManager() - 寻找事务管理器:

  4. 找到容器中配置的 PlatformTransactionManager Bean。

  5. createTransactionIfNecessary() - 创建事务(如果需要):

  6. 这是风暴的真正核心!

    它内部的逻辑会根据

     @Transactional
    

    传播行为 (propagation)

    做出不同决策:

    • PROPAGATION_REQUIRED (默认):
    • 检查当前线程是否已经存在一个事务。
    • 如果不存在,就调用 ptm.getTransaction(txAttr) 开启一个新的物理事务。这通常意味着执行 connection.setAutoCommit(false)
    • 如果存在,就加入到当前事务中,什么都不做,继续执行。
    • PROPAGATION_REQUIRES_NEW:
    • 不管当前是否存在事务,总是调用 ptm.getTransaction(txAttr) 开启一个全新的物理事务。如果当前已有事务,会先将它“挂起”。
    • PROPAGATION_NESTED:
    • 如果当前存在事务,则创建一个“嵌套事务”(利用数据库的 Savepoint 机制)。如果不存在,则行为同 REQUIRED
    • 其他传播行为以此类推…
  7. 最终,它会返回一个 TransactionInfo 对象,其中包含了事务状态 (TransactionStatus) 和事务管理器等信息。

  8. invocation.proceedWithInvocation() - 执行目标方法:

  9. 调用 AOP 调用链的 proceed() 方法,最终执行到我们 Service 中的业务逻辑代码,包括所有的 DAO 操作。

  10. 关键点: 由于事务已经开启,此时从 DataSource 获取的 Connection 都是同一个(通过 TransactionSynchronizationManager 绑定到当前线程),从而保证了所有数据库操作在同一个事务中。

  11. completeTransactionAfterThrowing() - 异常时回滚:

  12. 如果 proceed() 抛出了异常,此方法会被调用。

  13. 它会检查异常类型是否匹配 @Transactional 注解中 rollbackFornoRollbackFor 的规则。(默认只对 RuntimeExceptionError 回滚)。

  14. 如果判断需要回滚,则会调用 ptm.rollback(txInfo.getTransactionStatus()),这通常意味着执行 connection.rollback()

  15. cleanupTransactionInfo() - 清理现场:

  16. finally 块中,无论成功失败,都会清理 ThreadLocal 中保存的事务信息。

  17. commitTransactionAfterReturning() - 成功时提交:

  18. 如果目标方法顺利执行完毕,没有抛出需要回滚的异常,此方法会被调用。

  19. 它会调用 ptm.commit(txInfo.getTransactionStatus()),这通常意味着执行 connection.commit()

至此,一个由 @Transactional 控制的事务,走完了它严谨而恢弘的一生。

第四章:总结——事务管理的本质

经过这次终极探险,@Transactional 在我们面前再无秘密可言。它的本质,是 Spring Framework 各大核心组件的一次完美协同作战:

  1. IoC 容器 (基础):
  2. 负责管理 PlatformTransactionManagerDataSource 以及所有业务 Bean 的生命周期。
  3. Spring Boot 自动配置 (粘合剂):
  4. 智能地检测环境,自动为我们配置好 PlatformTransactionManager,并启用事务 AOP 功能,将所有组件无缝地粘合在一起。
  5. Spring AOP (执行者):
  6. 作为事务的“代理人”,通过 TransactionInterceptor 在目标方法执行前后织入事务控制逻辑,这是整个事务管理得以“无侵入式”实现的关键。
  7. PlatformTransactionManager (抽象核心):
  8. 这是 Spring 对不同事务资源(JDBC, JPA, JMS 等)的高度抽象。TransactionInterceptor 只与这个接口打交道,从而屏蔽了底层的实现差异。
  9. TransactionSynchronizationManager (线程绑定):
  10. 一个基于 ThreadLocal 的工具,它确保在同一个事务调用链中,所有部分获取到的都是同一个数据库连接 (Connection) 和同一个事务状态,这是事务能够跨方法、跨 DAO 生效的保障。

从 IoC 的萌芽,到 AOP 的切入;从 MVC 的请求,到 Boot 的装配;再到今天,事务的保障。我们这场历时五章的 Spring 源码探险,至此画上了一个圆满的句号。

我们不再是浮于表面的 API 调用者。我们亲眼见证了 Bean 如何诞生,代理如何生成,请求如何流转,配置如何加载,事务如何控制。我们理解了 Spring 框架背后那些优雅、精妙、贯穿始终的设计思想——抽象、分层、扩展、约定。

Code Tells All. 源码,已经告诉了我们一切。

这次探险的终点,是你对 Spring 乃至所有优秀框架建立全新认知的起点。当你未来面对任何一个“黑盒”技术时,愿你都能拥有深入其源码、探究其本质的勇气和能力。

山高路远,江湖再见!