升级后,异步事务性保存在 Spring 中不起作用
Async Transactional Saves do not work in Spring after upgrade
我们将 Spring 引导从 1.5.8 升级到 2.6.2。它引入了一个让我们困惑的问题:事务性保存不是从生成的线程内部处理的。
我们在 Mysql 数据库上使用 JPA 托管实体,并向下调用 CrudRepository 来保存它们。
主线程内的事务工作正常。但是,当从异步操作中调用时,事情会出错:
- 异步和同步调用都通过 Spring
SimpleJpaRepository.save()
方法。但是 entityManager returns 在异步操作的情况下,对象以 null id 持久化。
- 我跟踪了两种类型调用的流程,可以看到保存向下传播到
org.hibernate.internal.SessionImpl
服务。
- 从那里它到达 AbstractSaveEventListener.class,这就是差异出现的地方。在 performSaveOrReplicate 方法 (hibernate-core:5.6.3) 中,
inTrx
布尔值在异步工作流中为 false,而在同步工作流中为 true。因此,设置了 shouldDelayIdentityInserts
标志,并且似乎没有为该线程中的任何实体生成 ID。
我们尝试了不同的方法来让它发挥作用。例如,我们使用 transactionTemplate 在这里进行了一些特定的控制,但这并没有改变行为。
我们最初是通过使用 ApplicationEventPublisher 创建一个事件来创建这个异步进程的。我们还尝试使用 completablefuture 和其他具有相同结果的构造,以及使用 @Async 注释该方法并直接调用它。
问题是,随着升级到 Spring Boot 2.6,Spring Batch 实现了新的事务管理器。
我们没有意识到的是,这个事务管理器被自动连接到我们的其他服务中,并且没有在这个线程上下文中工作。您不想与 API/misc 服务共享批处理 Tx 管理器。在那里声明一个特定的事务管理器以将它们分开解决了这个问题。
我们将 Spring 引导从 1.5.8 升级到 2.6.2。它引入了一个让我们困惑的问题:事务性保存不是从生成的线程内部处理的。
我们在 Mysql 数据库上使用 JPA 托管实体,并向下调用 CrudRepository 来保存它们。
主线程内的事务工作正常。但是,当从异步操作中调用时,事情会出错:
- 异步和同步调用都通过 Spring
SimpleJpaRepository.save()
方法。但是 entityManager returns 在异步操作的情况下,对象以 null id 持久化。 - 我跟踪了两种类型调用的流程,可以看到保存向下传播到
org.hibernate.internal.SessionImpl
服务。 - 从那里它到达 AbstractSaveEventListener.class,这就是差异出现的地方。在 performSaveOrReplicate 方法 (hibernate-core:5.6.3) 中,
inTrx
布尔值在异步工作流中为 false,而在同步工作流中为 true。因此,设置了shouldDelayIdentityInserts
标志,并且似乎没有为该线程中的任何实体生成 ID。
我们尝试了不同的方法来让它发挥作用。例如,我们使用 transactionTemplate 在这里进行了一些特定的控制,但这并没有改变行为。
我们最初是通过使用 ApplicationEventPublisher 创建一个事件来创建这个异步进程的。我们还尝试使用 completablefuture 和其他具有相同结果的构造,以及使用 @Async 注释该方法并直接调用它。
问题是,随着升级到 Spring Boot 2.6,Spring Batch 实现了新的事务管理器。
我们没有意识到的是,这个事务管理器被自动连接到我们的其他服务中,并且没有在这个线程上下文中工作。您不想与 API/misc 服务共享批处理 Tx 管理器。在那里声明一个特定的事务管理器以将它们分开解决了这个问题。