JDBC和JMS的Spring事务同步

Posted

技术标签:

【中文标题】JDBC和JMS的Spring事务同步【英文标题】:Spring Transaction Synchronization of JDBC and JMS 【发布时间】:2012-03-03 00:40:30 【问题描述】:

我有一个在 jboss 上运行的 Spring Web 应用程序,当前配置为使用 HibernateTransactionManager 进行 db 事务,使用 JmsTransactionManager 进行 jms。对于 jms,我们使用 Camel 和 ActiveMQ,我们的数据库是 DB2。在一个事务中,我需要将一些记录写入数据库并发送两个异步 jms 消息。 jms 消息是事件通知,我只希望在数据库事务提交时发送它们。

我愿意承担在 jdbc 事务已经提交后与代理通信失败的风险(因此没有发送消息但已提交 db),所以我认为我不需要适当的 XA。

我相信我需要的是使用 Spring 事务同步的“尽力而为”的事务管理。

spring 文档暗示了这样一个事实,即 spring 将同步两个事务并仅在提交 jdbc 事务后提交 jms 事务 - 但我认为这不是很清楚。 http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-resource-synchronization 此处的 spring 文档没有详细说明它是如何工作的。

我发现其他几个来源说 spring 会做我想做的事,包括下面的一些 javadoc,我编写了一些也显示它的集成测试。

http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/jms/support/JmsAccessor.html#setSessionTransacted%28boolean%29 setSessionTransacted 上的 javadoc 听起来正是我想要的。

据我所见,我认为创建 Camel JmsConfiguration 并将事务设置为 true 就足够了:

<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
    <property name="connectionFactory" ref="pooledConnectionFactory"/>
    <property name="transacted" value="true"/>
    <property name="concurrentConsumers" value="10"/>
</bean>

但是,我需要说服与我一起工作的人,他有点怀疑并认为我的集成测试仅因为记录不充分的副作用而不是故意的弹簧功能才有效。

所以我的问题是 - 我是否正确,可以依靠 spring 来同步事务并始终在 jdbc 事务之后提交 jms 事务,或者这不是我应该依赖的东西,你能指点我吗?说明清楚的文件?我想总的来说,这是一个很好的方法,还是我们应该以不同的方式管理这些交易?

【问题讨论】:

您好,您的问题现在有答案了吗? 嗨,不是真的。我还没有看到任何我想要的非常清晰的文档,但我们现在在生产中使用它没有任何问题。 【参考方案1】:

这篇文章可能对Distributed transactions in Spring, with and without XA有帮助。我不认为它专门涵盖您的情况 - 发送消息 + 更新数据库。

【讨论】:

谢谢,我已经读过那篇文章几遍了。在 Best Efforts 1PC 部分中,他们提供了 Spring 同步的两个示例,但其中一个配置了 TransactionAwareConnectionFactoryProxy,另一个配置了 ChainedTransactionManager。如果我不需要做任何额外的配置来获得相同的结果,那我宁愿不要。【参考方案2】:

官方 Spring Boot 存储库包含基于 Atomikos、Bitronix 或 Java EE server JBoss WildFly 将 JMS 与 JDBC 相结合的 JTA 示例。

此外,我还创建了几个located in my Github repository 的示例。这也包含非 Spring Boot(纯 Spring)示例。

【讨论】:

指向您的 Git 存储库的链接不再有效。【参考方案3】:

如果您使用本地事务 用例保存到数据库,然后发送到 jms

那么可能有三种情况:

    接收后出现异常(DB 和 JMS 之前)

没问题,一切都会回滚

    保存到数据库后出现异常

如果有插入操作,由于重试,DB中会有多行。每次重试,都会插入一次。对于JMS,消息将进入DeadLetterQueue

    保存到 DB 并发送到 JMS 后,出现异常

    如果有插入操作,由于重试,DB中会有多行。每次重试,都会插入一次。对于JMS,消息将进入DeadLetterQueue

现在你不想使用 XA,所以解决方案可能是

1)检查 If(message.getJmsRedelivered() …

如果没有,处理它

如果它重新交付,请检查您是否已经处理它

根据消息中的详细信息检查数据是否在数据库中

请注意,重新交付很少见,因此,此检查也很少见,并且没有开销

2)如果你的方法是幂等的,那么你不需要这个检查

关于 XA , XA 保证消息只传递一次 并跨多个资源同步事务

但是使用 XA ,你有开销

因此,如果您可以在没有 XA 的情况下进行管理,则最好

【讨论】:

我无法理解您的 2 点。我的理解是,如果保存到 dB 后出现异常,则 dB 将回滚,jms 消息也会回滚。对吗?

以上是关于JDBC和JMS的Spring事务同步的主要内容,如果未能解决你的问题,请参考以下文章

Spring整合JMS——事务管理

Spring整合JMS

spring5的基本组成(6个模块)

spring jdbc 事务脏读怎么解决

Spring JMS 监听器中的事务管理

Spring Integration的DefaultMessageListenerContainer和JPA中的事务