深入理解 Spring 事务传播行为:从源码角度剖析事务管理的核心实现

引言

在现代企业级应用开发中,事务管理是确保数据一致性和系统可靠性的关键技术之一。Spring 框架作为 Java 开发的事实标准,提供了强大而灵活的事务管理机制。其中,事务传播行为作为 Spring 事务管理的核心概念,决定了多个事务方法之间如何协调工作。

本文将从源码角度深入分析 Spring 事务传播行为的实现机制,帮助开发者更好地理解事务管理的底层原理,从而在实际开发中做出更合理的技术决策。

一、Spring 事务管理的核心组件架构

Spring 事务管理采用了分层设计,核心组件包括事务管理器、事务定义和事务状态。这种设计使得事务管理与具体的数据源实现解耦,提供了高度的灵活性。

1.1 事务管理器接口

复制代码
// 事务管理器接口


public interface PlatformTransactionManager {


    TransactionStatus getTransaction(TransactionDefinition definition);


    void commit(TransactionStatus status);


    void rollback(TransactionStatus status);


}

PlatformTransactionManager 是事务管理的核心接口,定义了获取事务、提交事务和回滚事务三个基本操作。这个接口的设计体现了 Spring 的开闭原则,允许不同的数据源实现各自的事务管理逻辑。

1.2 事务定义接口

复制代码
// 事务定义接口


public interface TransactionDefinition {


    int PROPAGATION\_REQUIRED = 0;


    int PROPAGATION\_SUPPORTS = 1;


    int PROPAGATION\_MANDATORY = 2;


    // ... 其他传播行为常量


    


    int getPropagationBehavior();


    int getIsolationLevel();


    int getTimeout();


    boolean isReadOnly();


}

TransactionDefinition 接口定义了事务的基本属性,包括传播行为、隔离级别、超时时间和是否只读等。其中,传播行为是本文重点分析的内容。

1.3 事务状态接口

TransactionStatus 接口表示事务的当前状态,提供了获取事务状态、设置回滚标记等方法。

二、传播行为实现核心:AbstractPlatformTransactionManager

AbstractPlatformTransactionManager 是 PlatformTransactionManager 接口的抽象实现,提供了事务管理的通用逻辑。它是 Spring 事务传播行为实现的核心类。

2.1 getTransaction 方法分析

复制代码
@Override


public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {


    // 获取当前事务对象


    Object transaction = doGetTransaction();


    


    // 检查是否存在当前事务


    if (isExistingTransaction(transaction)) {


        // 处理存在事务的情况


        return handleExistingTransaction(definition, transaction, debugEnabled);


    }


    


    // 检查传播行为


    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_MANDATORY) {


        throw new IllegalTransactionStateException(


            "No existing transaction found for transaction marked with propagation 'mandatory'");


    } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_REQUIRED ||


               definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_REQUIRES\_NEW ||


               definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_NESTED) {


        // 挂起当前事务(如果有的话)


        SuspendedResourcesHolder suspendedResources = suspend(null);


        try {


            // 开始新事务


            return startTransaction(definition, transaction, debugEnabled, suspendedResources);


        } catch (RuntimeException | Error ex) {


            // 恢复挂起的事务


            resume(null, suspendedResources);


            throw ex;


        }


    } else {


        // 创建空事务


        return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);


    }


}

getTransaction 方法是事务管理的入口点,它根据当前是否存在事务和事务定义中的传播行为来决定如何处理事务。这个方法的核心逻辑可以分为三个主要部分:

  1. 获取当前事务对象:通过 doGetTransaction 方法获取当前线程的事务对象

  2. 检查是否存在事务:如果存在事务,则调用 handleExistingTransaction 方法处理

  3. 根据传播行为处理:如果不存在事务,则根据传播行为决定如何创建新事务

2.2 传播行为的分类处理

从源码中可以看出,Spring 对不同的传播行为进行了分类处理:

  • PROPAGATION_MANDATORY:要求必须存在事务,否则抛出异常

  • PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED:需要创建新事务的传播行为

  • 其他传播行为:创建空事务或非事务执行

三、处理已存在事务的核心逻辑

当当前线程已经存在事务时,Spring 会调用 handleExistingTransaction 方法来处理事务的传播行为。这个方法实现了各种传播行为在已有事务情况下的具体逻辑。

3.1 handleExistingTransaction 方法分析

复制代码
private TransactionStatus handleExistingTransaction(


        TransactionDefinition definition, Object transaction, boolean debugEnabled) {


    


    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_NEVER) {


        throw new IllegalTransactionStateException(


            "Existing transaction found for transaction marked with propagation 'never'");


    }


    


    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_NOT\_SUPPORTED) {


        // 挂起当前事务


        Object suspendedResources = suspend(transaction);


        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION\_ALWAYS);


        return prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);


    }


    


    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_REQUIRES\_NEW) {


        // 挂起当前事务,开始新事务


        SuspendedResourcesHolder suspendedResources = suspend(transaction);


        try {


            return startTransaction(definition, transaction, debugEnabled, suspendedResources);


        } catch (RuntimeException | Error beginEx) {


            resumeAfterBeginException(transaction, suspendedResources, beginEx);


            throw beginEx;


        }


    }


    


    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION\_NESTED) {


        // 嵌套事务处理


        if (useSavepointForNestedTransaction()) {


            DefaultTransactionStatus status = prepareTransactionStatus(


                definition, transaction, false, false, debugEnabled, null);


            status.createAndHoldSavepoint(); // 创建保存点


            return status;


        } else {


            return startTransaction(definition, transaction, debugEnabled, null);


        }


    }


    


    // PROPAGATION\_SUPPORTS or PROPAGATION\_REQUIRED


    return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);


}

3.2 各传播行为的具体实现

让我们逐一分析各个传播行为的实现逻辑:

3.2.1 PROPAGATION_NEVER

如果当前存在事务,而传播行为是 NEVER,则抛出 IllegalTransactionStateException 异常。这确保了标记为 NEVER 的方法不会在事务上下文中执行。

3.2.2 PROPAGATION_NOT_SUPPORTED

当传播行为是 NOT_SUPPORTED 时,Spring 会挂起当前事务,然后在非事务环境下执行方法。这对于那些不需要事务支持但又不能在事务中执行的操作非常有用。

3.2.3 PROPAGATION_REQUIRES_NEW

REQUIRES_NEW 是一个非常重要的传播行为,它会挂起当前事务,然后创建一个全新的事务。这意味着内部事务的提交和回滚不会影响外部事务。

3.2.4 PROPAGATION_NESTED

NESTED 传播行为实现了嵌套事务的概念。Spring 会在当前事务中创建一个保存点,内部事务的回滚只会回滚到这个保存点,而不会影响外部事务。

3.2.5 PROPAGATION_SUPPORTS 和 PROPAGATION_REQUIRED

这两个传播行为会直接使用当前事务,不会创建新事务。

四、数据库事务创建:DataSourceTransactionManager

DataSourceTransactionManager 是 PlatformTransactionManager 接口的具体实现,负责管理 JDBC 数据源的事务。

4.1 doGetTransaction 方法

复制代码
@Override


protected Object doGetTransaction() {


    DataSourceTransactionObject txObject = new DataSourceTransactionObject();


    txObject.setSavepointAllowed(isNestedTransactionAllowed());


    


    // 从ThreadLocal获取连接持有者


    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());


    txObject.setConnectionHolder(conHolder, false);


    return txObject;


}

doGetTransaction 方法负责获取当前线程的事务对象。它通过 TransactionSynchronizationManager 从 ThreadLocal 中获取连接持有者,这体现了 Spring 事务管理的线程隔离特性。

4.2 doBegin 方法

复制代码
@Override


protected void doBegin(Object transaction, TransactionDefinition definition) {


    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;


    Connection con = null;


    


    try {


        if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {


            // 从数据源获取新连接


            Connection newCon = obtainDataSource().getConnection();


            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);


        }


        


        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);


        con = txObject.getConnectionHolder().getConnection();


        


        // 设置事务属性


        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);


        txObject.setPreviousIsolationLevel(previousIsolationLevel);


        txObject.setReadOnly(definition.isReadOnly());


        


        // 关闭自动提交,开启事务


        if (con.getAutoCommit()) {


            txObject.setMustRestoreAutoCommit(true);


            con.setAutoCommit(false); // 关键:这里开始数据库事务


        }


        


        prepareTransactionalConnection(con, definition);


        txObject.getConnectionHolder().setTransactionActive(true);


        


        // 设置超时


        int timeout = determineTimeout(definition);


        if (timeout != TransactionDefinition.TIMEOUT\_DEFAULT) {


            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);


        }


        


        // 绑定连接到ThreadLocal


        if (txObject.isNewConnectionHolder()) {


            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());


        }


    } catch (Throwable ex) {


        if (txObject.isNewConnectionHolder()) {


            DataSourceUtils.releaseConnection(con, obtainDataSource());


            txObject.setConnectionHolder(null, false);


        }


        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);


    }


}

doBegin 方法是实际创建数据库事务的地方。它的核心逻辑包括:

  1. 获取数据库连接:如果当前线程没有连接持有者,则从数据源获取新连接

  2. 设置事务属性:设置事务的隔离级别、是否只读等属性

  3. 开启事务:通过调用 connection.setAutoCommit (false) 来开启数据库事务

  4. 绑定连接:将连接绑定到 ThreadLocal,确保线程隔离

五、事务同步管理:TransactionSynchronizationManager

TransactionSynchronizationManager 是 Spring 事务同步管理的核心类,它通过 ThreadLocal 来管理事务资源和同步回调。

5.1 TransactionSynchronizationManager 核心代码

复制代码
public abstract class TransactionSynchronizationManager {


    // ThreadLocal存储事务资源


&#x20;   private static final ThreadLocal\<Map\<Object, Object>> resources =&#x20;


&#x20;       new NamedThreadLocal<>("Transactional resources");


&#x20;  &#x20;


&#x20;   private static final ThreadLocal\<Set\<TransactionSynchronization>> synchronizations =&#x20;


&#x20;       new NamedThreadLocal<>("Transaction synchronizations");


&#x20;  &#x20;


&#x20;   private static final ThreadLocal\<String> currentTransactionName =&#x20;


&#x20;       new NamedThreadLocal<>("Current transaction name");


&#x20;  &#x20;


&#x20;   // 绑定资源到当前线程


&#x20;   public static void bindResource(Object key, Object value) throws IllegalStateException {


&#x20;       Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);


&#x20;       Map\<Object, Object> map = resources.get();


&#x20;       if (map == null) {


&#x20;           map = new HashMap<>();


&#x20;           resources.set(map);


&#x20;       }


&#x20;       Object oldValue = map.put(actualKey, value);


&#x20;      &#x20;


&#x20;       // 检查是否已存在绑定


&#x20;       if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {


&#x20;           oldValue = null;


&#x20;       }


&#x20;       if (oldValue != null) {


&#x20;           throw new IllegalStateException("Already value \[" + oldValue + "] for key \[" +&#x20;


&#x20;               actualKey + "] bound to thread \[" + Thread.currentThread().getName() + "]");


&#x20;       }


&#x20;   }


&#x20;  &#x20;


&#x20;   // 获取当前线程绑定的资源


&#x20;   public static Object getResource(Object key) {


&#x20;       Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);


&#x20;       Object value = doGetResource(actualKey);


&#x20;       return value;


&#x20;   }


}

5.2 ThreadLocal 的线程隔离机制

TransactionSynchronizationManager 使用 ThreadLocal 来存储事务资源,这确保了每个线程都有自己独立的事务上下文。这种设计使得 Spring 能够在多线程环境下安全地管理事务,每个线程都有自己的事务状态和资源。

ThreadLocal 的使用是 Spring 事务管理的关键技术之一,它解决了事务上下文的传递问题,使得事务管理代码更加简洁和优雅。

六、AOP 代理调用流程:TransactionInterceptor

Spring 事务管理是基于 AOP 实现的,TransactionInterceptor 是事务 AOP 的核心拦截器。

6.1 TransactionInterceptor 核心代码

复制代码
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor {


&#x20;   @Override


&#x20;   public Object invoke(MethodInvocation invocation) throws Throwable {


&#x20;       // 获取目标类


&#x20;       Class\<?> targetClass = (invocation.getThis() != null ?&#x20;


&#x20;           AopUtils.getTargetClass(invocation.getThis()) : null);


&#x20;      &#x20;


&#x20;       // 调用父类的invokeWithinTransaction方法


&#x20;       return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);


&#x20;   }


}

TransactionInterceptor 实现了 MethodInterceptor 接口,它会拦截所有标记了 @Transactional 注解的方法调用。

6.2 invokeWithinTransaction 方法

复制代码
protected Object invokeWithinTransaction(Method method, @Nullable Class\<?> targetClass,&#x20;


&#x20;       final InvocationCallback invocation) throws Throwable {


&#x20;  &#x20;


&#x20;   // 获取事务属性


&#x20;   TransactionAttributeSource tas = getTransactionAttributeSource();


&#x20;   final TransactionAttribute txAttr = (tas != null ?&#x20;


&#x20;       tas.getTransactionAttribute(method, targetClass) : null);


&#x20;   final TransactionManager tm = determineTransactionManager(txAttr);


&#x20;  &#x20;


&#x20;   if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {


&#x20;       // 响应式事务处理


&#x20;       // ...


&#x20;   }


&#x20;  &#x20;


&#x20;   PlatformTransactionManager ptm = asPlatformTransactionManager(tm);


&#x20;   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);


&#x20;  &#x20;


&#x20;   if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {


&#x20;       // 标准事务划分


&#x20;       TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);


&#x20;       Object retVal;


&#x20;       try {


&#x20;           // 执行目标方法


&#x20;           retVal = invocation.proceedWithInvocation();


&#x20;       } catch (Throwable ex) {


&#x20;           // 异常时回滚


&#x20;           completeTransactionAfterThrowing(txInfo, ex);


&#x20;           throw ex;


&#x20;       } finally {


&#x20;           cleanupTransactionInfo(txInfo);


&#x20;       }


&#x20;      &#x20;


&#x20;       if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {


&#x20;           // 处理Vavr Try类型


&#x20;           return VavrDelegate.evaluateTryFailure(retVal, txAttr, txInfo::getTransactionStatus);


&#x20;       }


&#x20;      &#x20;


&#x20;       // 正常提交


&#x20;       commitTransactionAfterReturning(txInfo);


&#x20;       return retVal;


&#x20;   } else {


&#x20;       // 回调首选的事务管理器处理


&#x20;       // ...


&#x20;   }


}

invokeWithinTransaction 方法是事务管理的核心流程,它的主要步骤包括:

  1. 获取事务属性:从 @Transactional 注解中获取事务属性

  2. 创建事务:调用 createTransactionIfNecessary 方法创建事务

  3. 执行目标方法:调用 invocation.proceedWithInvocation () 执行目标方法

  4. 异常处理:如果发生异常,调用 completeTransactionAfterThrowing 方法回滚事务

  5. 正常提交:如果方法正常执行,调用 commitTransactionAfterReturning 方法提交事务

七、关键执行流程总结

Spring 事务管理的关键执行流程可以总结为以下几个步骤:

复制代码
1\. @Transactional方法调用


↓


2\. TransactionInterceptor.invoke()


↓


3\. TransactionAspectSupport.invokeWithinTransaction()


↓


4\. AbstractPlatformTransactionManager.getTransaction()


↓


5\. 根据传播行为处理:


&#x20;  \- REQUIRED: 加入现有事务或创建新事务


&#x20;  \- REQUIRES\_NEW: 挂起现有事务,创建新事务


&#x20;  \- SUPPORTS: 支持现有事务,无事务则非事务执行


&#x20;  \- 其他传播行为...


↓


6\. DataSourceTransactionManager.doBegin()


↓


7\. Connection.setAutoCommit(false) - 实际开启数据库事务


↓


8\. 执行业务方法


↓


9\. 提交或回滚事务

7.1 核心要点回顾

  1. 传播行为实现:在 AbstractPlatformTransactionManager.getTransaction () 和 handleExistingTransaction () 中实现

  2. 数据库事务创建:在 DataSourceTransactionManager.doBegin () 中通过 Connection.setAutoCommit (false) 实现

  3. 线程绑定:通过 TransactionSynchronizationManager 的 ThreadLocal 实现事务资源的线程隔离

八、实际应用场景和最佳实践

理解了 Spring 事务传播行为的源码实现后,我们来看一些实际应用场景和最佳实践。

8.1 常见传播行为的应用场景

8.1.1 PROPAGATION_REQUIRED

这是默认的传播行为,适用于大多数业务场景。当一个事务方法调用另一个事务方法时,它们会共享同一个事务。

应用场景:订单创建和库存扣减需要在同一个事务中完成。

8.1.2 PROPAGATION_REQUIRES_NEW

当需要创建一个独立的事务时使用,内部事务的提交和回滚不会影响外部事务。

应用场景:日志记录、消息发送等操作,即使主事务失败也需要确保这些操作成功。

8.1.3 PROPAGATION_NESTED

实现嵌套事务,内部事务的回滚只会回滚到保存点,不会影响外部事务。

应用场景:批量操作中,部分操作失败时可以回滚到之前的状态。

8.1.4 PROPAGATION_NOT_SUPPORTED

在非事务环境下执行操作,适用于不需要事务支持的查询操作。

应用场景:报表生成、数据统计等只读操作。

8.2 最佳实践建议

  1. 合理选择传播行为:根据业务需求选择合适的传播行为,避免过度使用事务。

  2. 事务方法的粒度控制:事务方法的粒度不宜过大,也不宜过小。过大的事务会影响性能,过小的事务可能无法保证数据一致性。

  3. 异常处理:确保事务方法中的异常能够正确触发事务回滚。

  4. 只读事务:对于只读操作,设置 readOnly=true 可以提高性能。

  5. 事务超时:合理设置事务超时时间,避免长时间占用数据库连接。

九、总结与思考

通过对 Spring 事务传播行为源码的深入分析,我们可以看到 Spring 事务管理的设计之美。它采用了分层设计、接口抽象、策略模式等多种设计模式,使得事务管理既灵活又强大。

9.1 技术亮点

  1. ThreadLocal 的巧妙使用:通过 ThreadLocal 实现了事务上下文的线程隔离,解决了事务资源的传递问题。

  2. AOP 的优雅实现:基于 AOP 的事务管理使得业务代码和事务管理代码解耦,提高了代码的可维护性。

  3. 传播行为的灵活支持:通过传播行为的设计,Spring 支持了各种复杂的事务场景。

9.2 深入思考

  1. 性能优化:事务管理会带来一定的性能开销,如何在保证数据一致性的前提下优化性能是一个值得思考的问题。

  2. 分布式事务:在微服务架构下,分布式事务成为了新的挑战。Spring Cloud 提供了哪些解决方案?

  3. 响应式事务:随着响应式编程的兴起,Spring 也提供了响应式事务的支持。它的实现原理是什么?

9.3 学习建议

对于想要深入理解 Spring 事务管理的开发者,我建议:

  1. 阅读源码:直接阅读 Spring 事务管理的源码,这是最直接有效的学习方式。

  2. 动手实践:通过编写测试用例来验证各种传播行为的效果。

  3. 分析案例:分析开源项目中的事务管理实现,学习最佳实践。

结语

Spring 事务传播行为是 Spring 事务管理的核心概念,理解它的源码实现对于提升我们的技术水平具有重要意义。希望本文能够帮助读者更好地理解 Spring 事务管理的底层原理,从而在实际开发中做出更合理的技术决策。

在技术的道路上,我们需要不断学习和探索。Spring 框架作为 Java 开发的基石,其源码中蕴含着丰富的设计思想和最佳实践。希望大家能够保持对技术的热情,不断深入学习,成为更好的开发者。


参考资料

  • Spring Framework 官方文档

  • Spring 源码(版本:5.3.x)

  • 《Spring 实战》

  • 《深入理解 Spring Boot 与 Spring Cloud》

相关推荐
猎河增长官2 小时前
月考成绩分析总结与反思范文,查找薄弱环节与学习建议
经验分享
西门子918!4 小时前
西门子时间计数器
经验分享
资深数据库专家5 小时前
window 11 检测到一个 TDI 筛选器(\Driver\gwredirector)。该筛选器尚未通过 Microsoft 认证 。 如何解决
经验分享·微信·微信公众平台·新浪微博
不会学习?6 小时前
大二元旦,2025最后一天
经验分享·笔记
TeleostNaCl7 小时前
Android | 启用 TextView 跑马灯效果的方法
android·经验分享·android runtime
老臣软件7 小时前
告别卡顿焦虑
经验分享·mac·实用软件
么么...7 小时前
深入理解数据库事务与MVCC机制
数据库·经验分享·sql·mysql
sweetone10 小时前
ADAM ARTIST5多媒体有源音箱电路解析
经验分享·音视频
sweetone10 小时前
极微小故障维修实例 3篇
经验分享