Spring 事务管理源码分析
Spring 事务管理源码分析
为什么要了解事务源码
在实际项目中,我们经常会遇到这些问题:
- 为什么
@Transactional
不生效? - 为什么在同一个类里调用自己的方法事务失效?
- Spring 是怎么控制事务的开启、提交和回滚的?
rollbackFor
、Propagation
、Isolation
到底怎么生效的?
这些问题的根源,都藏在 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 |
|
Spring 会在容器启动时:
- 扫描到
@EnableTransactionManagement
- 注册
TransactionInterceptor
到 AOP 容器 - 为含
@Transactional
的 Bean 生成代理对象(JDK/CGLIB) - 调用时,由拦截器接管方法执行流程
调用链分析
当你执行:
1 | orderService.createOrder(); |
执行流程:
- 代理对象拦截调用
- Spring 生成的代理类先接收调用。
- 判断方法是否有
@Transactional
元信息。
- TransactionInterceptor 拦截执行
1
2
3
4
public Object invoke(MethodInvocation invocation) throws Throwable {
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
} - 获取事务属性
- 通过
TransactionAttributeSource
读取注解里的信息
(如传播行为、隔离级别、rollbackFor 等)
- 调用事务管理器开启事务实际上是调用:
1
txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
1
PlatformTransactionManager#getTransaction()
- 执行目标方法
1
retVal = invocation.proceed();
- 根据结果提交或回滚如果捕获到异常:
1
commitTransactionAfterReturning(txInfo);
1
completeTransactionAfterThrowing(txInfo, ex);
核心类:TransactionAspectSupport
事务控制的核心逻辑就在这里👇
1 | protected Object invokeWithinTransaction(Method method, Class<?> targetClass, InvocationCallback invocation) { |
📌 可以看到,事务的“开、提、回滚”全在这里完成。
DataSourceTransactionManager 核心逻辑
在 DataSourceTransactionManager
中:
开启事务:
1 | Connection con = dataSource.getConnection(); |
提交事务:
1 | con.commit(); |
回滚事务:
1 | con.rollback(); |
Spring 会通过 TransactionSynchronizationManager
把当前线程和连接绑定起来,实现多层嵌套事务共享同一连接。
为什么有时 @Transactional 不生效?
常见原因总结:
原因 | 说明 |
---|---|
1️⃣ 自调用 | 同一个类中方法互调,没经过代理 |
2️⃣ 方法不是 public | 事务代理默认只拦截 public 方法 |
3️⃣ 异常被 catch | 没抛出异常,Spring 不会回滚 |
4️⃣ 未被 Spring 管理 | 手动 new 出来的类没被代理 |
5️⃣ 数据源或事务管理器没配置正确 | Spring 没找到 PlatformTransactionManager |
调试建议
- 在
TransactionAspectSupport#invokeWithinTransaction()
打断点 - 观察
txInfo
对象中事务的状态 - 抛异常测试是否进入
completeTransactionAfterThrowing()
- 看
DataSourceTransactionManager#doCommit()
和doRollback()
的执行时机
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.