spring 事务是如何实现的?

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 绑定到 ThreadLocalTransactionSynchronizationManager.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 事务区别、多数据源切换等),可以告诉我,我可以继续拆更细。

文章已创建 4138

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部