提交后不久,交易的变更子集有时不可见

时间:2019-02-11 12:00:39

标签: java spring transactions spring-integration

让我们考虑以下情况:

2个spring集成通道,它们每个都在单独的数据库事务中。在第一笔交易结束时,一条消息被放入第二个通道。在第一个通道中,将在数据库中创建元素,这些元素随后会被从第一个通道发送到第二个通道的相应消息使用。

为确保在触发第二个通道之前,通道1的事务已完全提交,我们的JpaTransactionManager的子类正在TransactionSynchronization方法中注册一个prepareForCommit,它从JpaTransactionManager

流(通道1)如下所示:

  • 执行所有消息处理和数据库处理
  • 流程的最后一步是注册一个TransactionSynchronization,该MessageChannel.sendafterCommit阶段执行afterCommit,以将消息发送到通道2

我的理解是,在将消息发送到第二个通道(在Chain 1中时),通道1的数据库事务中所做的所有更改都被刷新并提交。

现在,第二个通道可以完成一些工作(例如MQ PUT),并随后更新在第一个流中创建的条目。现在我们已经观察到存储库方法在数据库中没有返回任何条目,但是稍后在表中可见。但是,在第一个通道的事务中也创建的其他条目是可见的。每隔几千条消息只会发生一次,通常它们在那里,但有时在通道1提交事务后的几毫秒内第二个通道看不到它们。

我创建了一张应该说明它的图像: enter image description here

ServiceActivators是第一个链,由多个执行数据库工作的ServiceActivator,一个生成更多消息的拆分器以及另一个我命名为SENDER的{​​{1}}组成。注册TransactionSynchronization,(据我所知)应该在红色事务完全提交之后,蓝色事务开始之前将例如3生成的消息发送到链2。

我注意到的一件事是,有时存在但有时不是全部的条目都属于一种(不是故意的)使用javax.transaction.Transactional而不是org.springframework.transaction.annotation.Transactional的方法。但是,我们使用的是 spring core 5.0.8.RELEASE ,在其他问题中,我发现自Spring 4.2.x以来,这应该有0的差异。

1 个答案:

答案 0 :(得分:1)

我认为afterCommit是向下游发送消息的正确位置。

应该足够有一个用@Transactional标记的POJO服务激活器。这样,事务将完全围绕此方法调用开始和完成。该方法的结果将在提交事务之后立即发送到输出通道。

更新

达到要求的最好方法是在Chain1上使用<gateway>。这样,在从网关生成对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