让我们考虑以下上下文:
2个spring集成 channel ,它们各自位于单独的数据库事务中。在第一个事务结束时,一条消息被放入第二个 channel 中。在第一个 channel 中,在数据库中创建元素,随后由从第一个 channel 发送到第二个 channel 的相应消息使用这些元素。
为了确保在触发第二个 channel 之前完全提交来自 channel 1 的事务,我们 JpaTransactionManager
的子类正在注册 TransactionSynchronization
在 prepareForCommit
它从 JpaTransactionManager
覆盖的方法
流程( channel 1)如下所示:
- 完成所有消息处理和数据库处理
- 流程的最后一步注册
TransactionSynchronization
这样做是MessageChannel.send
在afterCommit
将消息发送到 channel 2 的阶段
我的理解是,当消息发送到第二个 channel (在 afterCommit
中)时, channel 1 的数据库事务中所做的所有更改都将被刷新并提交。
现在,第二个 channel 执行一些工作(如 MQ PUT),并稍后更新在第一个流中创建的条目。我们现在观察到存储库方法在数据库中没有返回任何条目,但稍后在表中可见。然而,也在第一个 channel 的交易中创建的其他条目是可见的。这种情况每几千条消息才会发生一次,通常它们在那里,但有时在 channel 1 提交事务几毫秒后,它们对第二个 channel 不可见。
Chain 1
是第一个由多个 ServiceActivators
组成的链执行数据库工作,一个生成更多消息的拆分器,然后生成另一个 ServiceActivator
我命名为SENDER
它注册了 TransactionSynchronization
(据我的理解)应该在红色事务完全提交之后(因此在蓝色事务开始之前)将例如 3 条生成的消息发送到链 2。
我注意到的一件事是,有时存在、有时不存在的条目都在(不是故意)使用 javax.transaction.Transactional
的一种方法中。而不是org.springframework.transaction.annotation.Transactional
。但是,我们正在使用 spring core 5.0.8.RELEASE,在其他问题中我发现,自 spring 4.2.x 以来,这应该产生 0 差异。
最佳答案
我不认为afterCommit
是向下游发送消息的正确位置。
应该足以让 POJO 方法的服务激活器标记为 @Transactional
。这样,事务将完全围绕该方法调用开始和结束。该方法的结果将在事务提交后立即发送到输出 channel 。
更新
实现您的要求的最佳方式是 <gateway>
围绕您的 Chain1。这样,在从网关向 Chain2 生成回复之前,TX 将被提交到那里。
与 TransactionSynchronization::afterCommit
当 QueueChannel 准备好轮询消息时,无法保证 TX 将在 DB 上提交。虽然您可以使用 JdbcChannelMessageStore
用于消息的事务存储。这样,在 TX 在数据库中提交之前,它们将不可见。
查看更多有关<gateway>
的信息在文档中:https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-routing-chapter.html#_calling_a_chain_from_within_a_chain
关于java - 事务更改的子集有时在提交后不久不可见,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54630155/