Spring 的事务实现本质上是基于 AOP(面向切面编程) + 动态代理,在不修改原有业务代码的情况下,把事务的开始、提交、回滚、异常处理这些横切关注点“织入”到目标方法中。
下面从最核心的几个层面逐步拆解(以声明式事务 @Transactional 为例,这是 95%+ 项目实际使用的模式):
1. 整体架构分层(最重要的一张思维导图)
Spring 事务抽象层(PlatformTransactionManager)
↑
具体实现(DataSourceTransactionManager / JpaTransactionManager / JtaTransactionManager 等)
↑
TransactionSynchronizationManager(线程本地资源管理器)
↑
AOP 切面(TransactionInterceptor + 各种 Advice)
↑
动态代理(JDK Proxy / CGLIB)
↑
你的业务 Bean(@Service 中的 @Transactional 方法)
2. 核心实现步骤(运行时发生了什么)
| 阶段 | 发生了什么 | 关键类 / 组件 |
|---|---|---|
| 容器启动 | 解析 @EnableTransactionManagement 或 <tx:annotation-driven/> | TransactionManagementConfigurer / AnnotationDrivenBeanDefinitionParser |
注册 BeanFactoryTransactionAttributeSourceAdvisor(事务切面 Advisor) | ||
| Bean 创建 | 对于有 @Transactional 的类/方法,Spring 创建代理对象 | ProxyFactory / CglibAopProxy / JdkDynamicAopProxy |
| 外部调用方法时 | 调用的是代理对象的方法(不是原始对象) | |
| 代理拦截 | TransactionInterceptor(核心 Advice)被执行 | TransactionInterceptor.invoke() |
读取 @Transactional 的属性(propagation、isolation、timeout、rollbackFor 等) | TransactionAttributeSource | |
| 事务开始 | 调用 PlatformTransactionManager.getTransaction(definition) | → 创建 / 加入 / 挂起事务 |
| 把 Connection / TransactionStatus 绑定到 ThreadLocal | TransactionSynchronizationManager.bindResource() | |
| 目标方法执行 | 真正执行你的业务代码(原始对象的方法) | |
| 正常结束 | 提交:commit() | TransactionManager.commit(status) |
| 异常抛出 | 判断是否需要回滚(默认 RuntimeException & Error 回滚,可自定义 rollbackFor) | rollbackOn() 判断 |
回滚:rollback() | TransactionManager.rollback(status) | |
| 清理 | 解绑 ThreadLocal 资源,恢复挂起的旧事务(如果有嵌套) | cleanupTransaction() |
3. 传播行为(Propagation)是怎么实现的?(最常考点)
| 传播级别 | 代码中是否有事务 | 外面有事务吗? | 实际效果 | 底层实现方式简述 |
|---|---|---|---|---|
| REQUIRED | 无 | 无 | 新开事务 | getTransaction() 创建新事务 |
| REQUIRED | 有 | 有 | 加入已有事务 | 复用已有 TransactionStatus |
| REQUIRES_NEW | — | 有 | 总是新建独立事务(外面事务被挂起) | suspend() → create new → resume() |
| NESTED | — | 有 | 使用 savepoint(嵌套子事务) | createSavepoint() / rollbackToSavepoint() |
| SUPPORTS | — | 有 | 跟随外面事务,没有就不用事务 | 只读模式或无事务 |
| MANDATORY | — | 无 | 抛异常(必须在事务中调用) | 检查当前是否有事务,没有就 IllegalState |
| NEVER | — | 有 | 抛异常(禁止在事务中调用) | 同上 |
| NOT_SUPPORTED | — | 有 | 挂起外面事务,以非事务方式执行 | suspend() → 执行 → resume() |
注意:NESTED 是唯一基于 savepoint 的传播行为,其他的都是基于 Connection 的 commit/rollback。
4. 为什么自调用(this.method())事务会失效?
因为代理只对外部调用有效。
@Service
public class UserService {
@Transactional
public void outer() {
// 这里有事务
inner(); // ← this.inner() 直接调用原始对象的方法 → 绕过代理 → 无事务
}
@Transactional
public void inner() {
// 期望有事务,但实际没有(自调用场景)
}
}
解决办法(任选其一):
- 用
@Transactional的类注入自己(不推荐,循环依赖) - 用
AopContext.currentProxy()(需开启 exposeProxy=true) - 把 inner 抽到另一个
@Service类里(最推荐) - 用编程式事务
TransactionTemplate
5. 线程安全 & 资源绑定核心 —— TransactionSynchronizationManager
这是一个ThreadLocal大管家,里面存了:
- 当前线程的 Connection / Session / TransactionStatus
- 资源是否只读
- 事务同步器列表(可以注册回调:beforeCommit、afterCommit、afterCompletion 等)
几乎所有事务相关的操作最终都会走到这里取/放资源。
总结一句话
Spring 事务的实现可以浓缩为:
“用动态代理(AOP)拦截方法 → 根据 @Transactional 属性通过 PlatformTransactionManager 在 ThreadLocal 中绑定/管理数据库连接和事务状态 → 在方法正常结束或异常时统一 commit/rollback”。
最核心的两句话:
- 没有 AOP 动态代理 → 就没有声明式事务
- 没有 PlatformTransactionManager → 就没有真正的事务控制(Spring 只做协调)
如果你想更深入看某一块(比如 savepoint 实现细节、DataSourceTransactionManager 源码、Reactive 事务区别、多数据源切换等),可以告诉我,我可以继续拆更细。