首页 > 解决方案 > 在 Spring 应用程序的事务中使用异步

问题描述

我有一个 Spring 应用程序,它使用一种@Transactional方法更新 MySQL DB 中的特定实体详细信息,并且在同一个方法中,我试图调用另一个端点,使用@Async它是另一个 Spring 应用程序,它从 MySql DB 读取相同的实体并更新值redis 存储。

现在的问题是,每次我为实体更新一些值时,有时它会在 redis 中更新,有时则不会。

当我尝试调试时,我发现有时第二个应用程序从 MySql 读取实体时会选择旧值而不是更新值。

谁能建议我可以做些什么来避免这种情况并确保第二个应用程序始终从 Mysql 中选择该实体的更新值?

标签: mysqlspringasynchronousredistransactional

解决方案


M. Deinum 的回答很好,但还有另一种方法可以实现这一点,这对您来说可能更简单,具体取决于您当前应用程序的状态。

您可以简单地将对 async 方法的调用包装在将在当前事务提交后处理的事件中,这样您就可以每次都正确地从数据库中读取更新的实体。

这样做很简单,让我告诉你:

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

 @Transactional
public void doSomething() {

    // application code here

    // this code will still execute async - but only after the
    // outer transaction that surrounds this lambda is completed.
    executeAfterTransactionCommits(() -> theOtherServiceWithAsyncMethod.doIt());

    // more business logic here in the same transaction
}

private void executeAfterTransactionCommits(Runnable task) {
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
        public void afterCommit() {
            task.run();
        }
    });
}

基本上这里发生的情况是我们为当前事务回调提供了一个实现,我们只覆盖了 afterCommit 方法——那里还有其他可能有用的方法,请检查它们。如果您想在其他部分使用它或只是使该方法更具可读性,为了避免键入相同的样板代码,我将其提取到一个辅助方法中。


推荐阅读