【发布时间】:2022-01-23 01:32:39
【问题描述】:
我有一个方法,我想执行两个事务:一个使用 DB,一个使用 JMS。我希望一个接一个地提交。我正在尝试为此使用PlatformTransactionManager。有两种方法可以做到这一点:使用TransactionTemplate 或DefaultTransactionDefinition。但是我没有找到任何一个多次使用的例子。我想做的是:
void do(){
T dbTransaction = ...; // here goes: new TransactionTemplate(transactionManager) two times
T jmsTransaction = ...; // or: new DefaultTransactionDefinition() and transactionManager.getTransaction(definition); two times
saveDb();
sendJms();
dbTransaction.commit();
jmsTransaction.commit();
}
但我不确定要使用什么以及如何使用,因为在 this article 中它说:
无论如何,一旦我们创建了一个带有配置的 TransactionTemplate,所有事务都将使用该配置来执行。所以,如果我们需要多个配置,我们应该创建多个模板实例。
那么我如何正确地创建两个事务并一个接一个地关闭呢?我应该创建两个单独的definitions 还是可以重复使用一个?我可以在两个templates 中重复使用相同的transactionManager 吗?我知道 DB 有一个 @Transcational 注释,我也可以将 JMS 配置为使用事务,但是:
- 我没有找到如何配置 JMS 以使用事务的好示例
- 我不确定他们会在哪个订单关闭
所以我想手动执行此操作。我也不确定此手动事务是否适用于 JMS(例如 IBM-MQ),因为我只看到了数据库事务的示例。
【问题讨论】:
-
您实际上是否分别在每个
saveDb()和sendJms()方法中执行多个数据库和JMS 操作?如果没有,则使用事务没有任何好处。此外,通常在这种情况下,您希望数据库和 JMS 操作在 相同 事务中,而不是在 2 个不同的事务中。你不需要你的数据库和 JMS 操作是原子的吗?如果数据库事务提交成功,JMS 事务失败回滚怎么办? -
@JustinBertram,DB 中有一项操作,JMS 中有一项操作。但问题是,使用 @Transactional 它在保存到 DB 之前发送到 JMS,并且在确认它成功发送到 JMS 比它在 DB 中的速度更快之后我收到。在手动场景中,如果 JMS 失败,它将失败,但如果 JMS 没有异常,则会将其保存到 DB,即使在与 JMS 的事务失败之后我也可以,因为我将状态保存在 DB 中。
-
@JustinBertram
If not, there's no benefit to using a transaction.我认为能够重构代码(可能拆分查询)而不必担心未来的原子性是一个巨大的好处。事实上,我认为每次写入都应该是事务性的,并有明确的选择退出。但是,完全同意您的其余观点。 -
鉴于您的功能要求(即发送 JMS 消息时需要存在数据库中的数据),我认为您实际上 确实 希望这两个操作都在相同的事务,并且由于您正在使用多个资源管理器,因此您将希望使用 XA 事务。这不能与
@Transactional一起使用这一事实仅意味着某些配置不正确(例如,您的应用程序可能没有为 JDBC 和 JMS 使用正确的 XA 资源)。我不是 Spring 专家(我在 ActiveMQ 上工作)所以我不能推荐一个具体的解决方案,但我绝对认为你需要 XA。 -
不需要XA,只需要两个同步的本地事务。
标签: java spring-transactions spring-jms