Spring 事务管理源码分析

为什么要了解事务源码

在实际项目中,我们经常会遇到这些问题:

  • 为什么 @Transactional 不生效?
  • 为什么在同一个类里调用自己的方法事务失效?
  • Spring 是怎么控制事务的开启、提交和回滚的?
  • rollbackForPropagationIsolation 到底怎么生效的?
    这些问题的根源,都藏在 Spring 的 事务代理机制事务拦截器源码 里。

Spring 事务核心架构

graph TD
    A["@Transactional 方法调用"]
    B[TransactionInterceptor]
    C[PlatformTransactionManager]
    D[DataSourceTransactionManager]
    E[(数据库连接)]
    F[执行目标方法]
    G[回滚事务]
    H[提交事务]

    A --> B
    B --> C
    C --> D
    D --> E
    B --> F
    F --> G
    F --> H

核心组件:

组件 作用
@Transactional 声明事务边界(告诉 Spring 哪个方法需要事务)
TransactionInterceptor AOP 拦截器,拦截方法调用
PlatformTransactionManager 管理事务的接口(开启/提交/回滚)
DataSourceTransactionManager 基于 JDBC 的事务实现
TransactionAspectSupport 实际处理事务逻辑的核心类

从 @Transactional 开始

当你在方法上加上:

1
2
@Transactional
public void createOrder() { ... }

Spring 会在容器启动时:

  1. 扫描到 @EnableTransactionManagement
  2. 注册 TransactionInterceptor 到 AOP 容器
  3. 为含 @Transactional 的 Bean 生成代理对象(JDK/CGLIB)
  4. 调用时,由拦截器接管方法执行流程

调用链分析

当你执行:

1
orderService.createOrder();

执行流程:

  1. 代理对象拦截调用
  • Spring 生成的代理类先接收调用。
  • 判断方法是否有 @Transactional 元信息。
  1. TransactionInterceptor 拦截执行
    1
    2
    3
    4
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }
  2. 获取事务属性
  • 通过 TransactionAttributeSource 读取注解里的信息
    (如传播行为、隔离级别、rollbackFor 等)
  1. 调用事务管理器开启事务
    1
    txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
    实际上是调用:
    1
    PlatformTransactionManager#getTransaction()
  2. 执行目标方法
    1
    retVal = invocation.proceed();
  3. 根据结果提交或回滚
    1
    commitTransactionAfterReturning(txInfo);
    如果捕获到异常:
    1
    completeTransactionAfterThrowing(txInfo, ex);

核心类:TransactionAspectSupport

事务控制的核心逻辑就在这里👇

1
2
3
4
5
6
7
8
9
10
11
12
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, InvocationCallback invocation) {
TransactionInfo txInfo = createTransactionIfNecessary(...);

try {
Object retVal = invocation.proceed(); // 执行目标方法
commitTransactionAfterReturning(txInfo); // 正常提交
return retVal;
} catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex); // 异常回滚
throw ex;
}
}

📌 可以看到,事务的“开、提、回滚”全在这里完成。

DataSourceTransactionManager 核心逻辑

DataSourceTransactionManager 中:
开启事务:

1
2
Connection con = dataSource.getConnection();
con.setAutoCommit(false);

提交事务:

1
con.commit();

回滚事务:

1
con.rollback();

Spring 会通过 TransactionSynchronizationManager 把当前线程和连接绑定起来,实现多层嵌套事务共享同一连接。

为什么有时 @Transactional 不生效?

常见原因总结:

原因 说明
1️⃣ 自调用 同一个类中方法互调,没经过代理
2️⃣ 方法不是 public 事务代理默认只拦截 public 方法
3️⃣ 异常被 catch 没抛出异常,Spring 不会回滚
4️⃣ 未被 Spring 管理 手动 new 出来的类没被代理
5️⃣ 数据源或事务管理器没配置正确 Spring 没找到 PlatformTransactionManager

调试建议

  1. TransactionAspectSupport#invokeWithinTransaction() 打断点
  2. 观察 txInfo 对象中事务的状态
  3. 抛异常测试是否进入 completeTransactionAfterThrowing()
  4. DataSourceTransactionManager#doCommit()doRollback() 的执行时机