升级后异步事务保存在 Spring 中不起作用

发布于 2025-01-11 22:55:09 字数 800 浏览 0 评论 0原文

我们将 Spring Boot 从 1.5.8 升级到 2.6.2。它引入了一个让我们困惑的问题:事务保存不是从生成的线程内部进行处理的。

我们在 Mysql 数据库上使用 JPA 托管实体,并调用 CrudRepository 来保存它们。

主线程内的事务工作正常。然而,当从异步操作调用时,事情就会出错:

  • 异步和同步调用都通过 Spring SimpleJpaRepository.save() 方法。但在异步操作的情况下,entityManager 返回的对象以 null id 持久保存。
  • 我跟踪了这​​两种类型的调用流程,可以看到保存传播到了 org.hibernate.internal.SessionImpl 服务。
  • 从那里它进入 AbstractSaveEventListener.class,这就是出现差异的地方。在 PerformSaveOrReplicate 方法 (hibernate-core:5.6.3) 中,inTrx 布尔值在异步工作流程中为 false,而在同步工作流程中为 true。因此,shouldDelayIdentityInserts 标志被设置,并且似乎不会为该线程中的任何实体生成 id。

我们尝试了不同的方法来使其发挥作用。例如,我们在这里使用 transactionTemplate 进行一些特定的控制,但这并没有改变行为。

我们最初是通过使用 ApplicationEventPublisher 创建事件来创建此异步流程。我们还尝试使用 completablefuture 和其他具有相同结果的构造,以及使用 @Async 注释该方法并直接调用它。

We upgraded Spring Boot from 1.5.8 to 2.6.2. It has introduced a problem that has us perplexed: Transactional saves are not processing from inside spawned threads.

We use JPA managed entities on a Mysql database and make calls down to the CrudRepository to save them.

Transactions inside the main thread work fine. However, when called from an asynchronous operation things go awry:

  • both async and sync calls go through the Spring SimpleJpaRepository.save() method. But the entityManager returns the object to persist with a null id in the case of the async operation.
  • I followed the flow through in both types of calls and can see that the save propagates down to the org.hibernate.internal.SessionImpl service.
  • From there it makes its way to AbstractSaveEventListener.class and that is where the discrepancy appears to be. In the performSaveOrReplicate method (hibernate-core:5.6.3), inTrx boolean is false in the async workflow whereas it is true in the synch one. Because of that the shouldDelayIdentityInserts flag gets set and an id does not appear to be generated for any entities in this thread.

We have tried different things to get this to work. For example, we used the transactionTemplate to have some specific control here, but that has not changed the behavior.

We were originally creating this async process by using the ApplicationEventPublisher to create an event. We also tried using completablefuture and other constructs with the same result as well as annotating the method with @Async and calling it directly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ι不睡觉的鱼゛ 2025-01-18 22:55:09

问题是,随着升级到 Spring Boot 2.6,Spring Batch 实现了新的事务管理器。

我们没有意识到的是,这个事务管理器被自动连接到我们的其他服务中,并且在这个线程上下文中不起作用。您不想与 API/杂项服务共享批处理 Tx 管理器。在那里声明一个特定的事务管理器以将它们分开解决了这个问题。

下面是一个使用 Primary 注释标记 PlatformTransactionManager 以显式测试其用法的示例。

@Primary
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory(dataSource).getObject());
    return transactionManager;
}

The issue was that, with the upgrade to Spring Boot 2.6, Spring Batch implements a new Transaction Manager.

What we didn't realize is that this transaction manager was being autowired into our other services and did not work in this threaded context. You do not want to share a Batch processing Tx Manager with your API/misc services. Declaring a specific Transaction Manager there to keep them separate solved the issue.

Here is an example marking a PlatformTransactionManager with the Primary annotation to test its usage explicitly.

@Primary
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory(dataSource).getObject());
    return transactionManager;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文