Spring技巧

Spring在事务提交之后 执行异步方法

2025-03-31  本文已影响0人  饱饱抓住了灵感

在 Spring 中,若要让异步方法在事务提交后执行,可以通过 事务同步机制(TransactionSynchronization) 结合 异步执行 实现。


一、核心思路

  1. 事务内注册回调:在事务方法中,通过 TransactionSynchronizationManager 注册一个事务提交后的回调。
  2. 异步触发逻辑:在回调的 afterCommit() 方法中调用异步方法,确保异步逻辑在事务提交后执行。

二、实现步骤

1. 开启事务和异步支持

在配置类中启用事务和异步功能:

@Configuration
@EnableTransactionManagement
@EnableAsync
public class AppConfig {
    // 配置线程池(可选,默认使用 SimpleAsyncTaskExecutor)
    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.initialize();
        return executor;
    }
}

2. 定义异步方法

在 Service 中定义异步方法,使用 @Async 注解:

@Service
public class AsyncService {
    @Async("taskExecutor") // 指定线程池
    public void asyncMethodAfterCommit(String data) {
        System.out.println("异步执行,线程:" + Thread.currentThread().getName());
        // 异步业务逻辑
    }
}

3. 在事务中注册回调

在事务方法中,通过 TransactionSynchronizationAdapter 注册事务提交后的回调:

@Service
public class TransactionalService {

    @Autowired
    private AsyncService asyncService;

    @Transactional
    public void transactionalMethod() {
        // 业务逻辑...
        System.out.println("事务内操作,线程:" + Thread.currentThread().getName());

        // 注册事务提交后的回调
        TransactionSynchronizationManager.registerSynchronization(
            new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    // 事务提交后执行异步方法
                    asyncService.asyncMethodAfterCommit("data");
                }
            }
        );
    }
}

三、关键点说明

  1. 事务与异步的协作
    • 直接调用 asyncMethodAfterCommit() 会立即异步执行,但无法保证事务已提交。
    • 通过 TransactionSynchronizationAdapter.afterCommit(),确保异步逻辑仅在事务成功提交后触发。
  2. 事务传播行为影响
    • 如果事务是 REQUIRED(默认传播行为),异步方法会在原事务提交后执行。
    • 若事务回滚,afterCommit() 不会触发,异步方法也不会执行。
  3. 线程安全
    • 异步方法需避免共享可变状态,或通过同步机制保证线程安全。

四、afterCommit的核心规则

执行顺序

  1. 事务提交时机
    事务的提交操作发生在事务方法返回之前(由 Spring AOP 代理确保)。
  2. 回调触发时机
    afterCommit() 回调会在事务提交成功后触发,但仍在事务方法返回的同一线程中执行。
  3. 代码执行顺序
    事务方法内部的代码 → 事务提交 → 回调执行 → 事务方法返回 → 调用方后续逻辑。

示例

@Service
public class TestService {

    @Transactional
    public void transactionalMethod() {
        System.out.println("事务内操作");
        // 注册回调
        TransactionSynchronizationManager.registerSynchronization(
            new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    System.out.println("回调执行:事务已提交");
                }
            }
        );
        System.out.println("事务方法即将返回");
    }

}

@Service
public class InvokeService{
    @Resource
    private TestService testService;
    
    public void callerMethod() {
        testService.transactionalMethod(); // 调用事务方法
        System.out.println("调用方后续逻辑");
    }
}

输出结果

事务内操作
事务方法即将返回
回调执行:事务已提交
调用方后续逻辑

结论

  1. 事务提交与回调的关系

    • 事务提交发生在事务方法返回之前(由 Spring 代理管理)。
    • afterCommit() 回调在事务提交完成后触发,但仍在事务方法返回的线程中同步执行。
    • 因此,事务方法返回后,回调会立即执行,随后才是调用方的后续逻辑。
  2. 线程模型

    • 默认情况下,事务方法和回调在同一线程中执行,确保顺序性。
    • 若回调中调用 @Async 异步方法,则异步逻辑会转移到其他线程,但 afterCommit() 本身仍会在原线程中完成。
  3. 适用场景:需确保回调逻辑在事务提交后执行,但对实时性要求不高的场景(如发送通知、更新缓存)。


五、注意事项

上一篇 下一篇

猜你喜欢

热点阅读