Administrator
发布于 2025-03-13 / 7 阅读
0
0

判断当前代码是否处于事务内

Spring框架提供了一种方便的方式来判断当前是否在事务内,可以使用TransactionSynchronizationManager来实现。

有2个方法:isSynchronizationActiveisActualTransactionActive 。这2个方法,都可以用来判断,当前是否在事务内。只不过有一些区别:

1. ​判断依据不同

  • isSynchronizationActive()
    检查当前线程是否已初始化事务同步器(即synchronizations线程变量是否非空)。

当Spring事务管理器开启事务时,会调用initSynchronization(),初始化同步器集合(即使事务未提交),此时返回true。

示例场景:事务初始化阶段(如刚进入@Transactional方法)可能已激活同步,但事务本身还未提交或回滚。

  • isActualTransactionActive()
    直接检查actualTransactionActive线程变量,该变量仅在事务真正处于活跃状态(从事务开始到提交/回滚前)时设为true。

示例场景:在事务执行过程中(如执行数据库操作时)返回true,而事务提交后或未开启事务时返回false。

2.​生命周期阶段的覆盖范围

  • isSynchronizationActive()
    可能在事务初始化时即激活​(如事务传播行为为REQUIRED且方法进入@Transactional注解范围时),甚至在事务挂起(如嵌套事务)时仍可能返回true。

  • isActualTransactionActive()
    仅在事务实际执行阶段​(从begin到commit/rollback)返回true。若事务被挂起(如调用TransactionTemplate暂停当前事务),则返回false。

isActualTransactionActive详解

TransactionSynchronizationManager.isActualTransactionActive() 方法用于判断当前线程是否关联一个实际激活的事务。其返回值取决于事务上下文的实际状态,具体逻辑如下:


返回 true 的情况

  1. 事务内部调用
    当方法在声明式事务(如 @Transactional 注解标记的方法)内部调用时,Spring 会通过 ThreadLocal 绑定事务资源到当前线程。此时,若事务未被挂起或回滚,该方法返回 true

  2. 事务传播行为未挂起
    在嵌套事务或事务传播行为(如 PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEW)生效时,若外层事务未被挂起(suspend()),则内层事务的 isActualTransactionActive() 仍返回 true


返回 false 的情况

  1. 非事务上下文
    若当前方法未开启事务(如未使用 @Transactional 注解),或事务已提交/回滚,则该方法返回 false

  2. 事务被挂起
    当外层事务通过 suspend() 方法挂起时,即使当前线程仍存在事务同步(isSynchronizationActive() 返回 true),isActualTransactionActive() 也会返回 false。这是因为挂起操作会清除 ThreadLocal 中的 actualTransactionActive 标记。

  3. 事务传播行为导致挂起
    例如,在 PROPAGATION_REQUIRES_NEW 传播行为中,外层事务会被挂起以启动新事务。此时在外层事务的代码块中调用该方法,会返回 false,而内层事务返回 true


内部实现机制

该方法通过 ThreadLocal<Boolean> actualTransactionActive 存储事务活跃状态。当 Spring 启动事务时,会将该值设为 true;提交、回滚或挂起事务时,则会重置为 false


典型使用场景

  • 事务回调注册:在注册事务同步器(registerSynchronization())前,需先通过该方法检查事务是否活跃,否则会抛出异常。
  • 异步任务控制:若需在事务提交后执行异步操作(如发送消息),可通过该方法判断是否需延迟执行,避免数据不一致。

总结

条件返回值引用来源
事务内部未挂起true
非事务方法或事务已结束false
事务被挂起false

如需更深入的实现细节,可参考 Spring 源码中 TransactionSynchronizationManagerThreadLocal 状态的管理逻辑。

3.​适用场景对比

方法典型使用场景注意事项
isSynchronizationActive()注册事务同步回调(如afterCommit钩子)时,需确保同步机制已激活若未激活同步时注册回调会抛出IllegalStateException,需先调用此方法判断
isActualTransactionActive()判断业务逻辑是否需依赖事务执行(如某些操作必须在事务中执行)不反映事务同步状态,仅关注事务活跃性。

4。工作中的实例

 private boolean determineStartTransaction() {
        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            return false;
        } else {
            return true;
        }
    }
public <T> Long deleteLongWithTransaction(Function<T, Long> function, T condition) {
        if (!determineStartTransaction()) {
            return function.apply(condition);
        } else {
            DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
            defaultTransactionDefinition.setName("deleteLongOneTx");
            defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            TransactionStatus txStatus = platformTransactionManager.getTransaction(defaultTransactionDefinition);
            try {
                Long affectedRows = function.apply(condition);
                platformTransactionManager.commit(txStatus);
                return affectedRows;
            } catch (Exception e) {
                platformTransactionManager.rollback(txStatus);
                throw e;
            }
        }
    }

评论