JDBC和JMS的Spring事务同步

时间:2012-02-10 14:47:46

标签: java spring transactions jms apache-camel

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

我愿意接受在jdbc事务已经提交之后与代理通信失败的风险(因此没有发送消息但是db已经提交)所以我认为我不需要正确的XA。

我认为我需要的是使用spring transaction synchronization同步的“尽力而为”的事务管理。

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

我发现其他一些消息来源说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事务,或者这不是我应该依赖的东西,你能否指出我的任何官员明确说明的文件?我想一般来说这是一个很好的方法,或者我们应该以不同的方式管理这些交易吗?

3 个答案:

答案 0 :(得分:3)

这篇文章可能有所帮助Distributed transactions in Spring, with and without XA。我不认为它具体涵盖您的案例 - 发送消息+更新数据库。

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

如果您使用的是本地交易 并将用例保存到数据库,然后发送到jms

然后可能有三种情况:

  1. 收到后(DB和JMS之前)的异常
  2.   
        

    没问题,一切都会被回滚

      
    1. 保存到DB后,我们有例外
    2.   
          

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

        
      1. 保存到DB并发送到JMS后,我们有一个例外
          
            

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

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

        1)检查If(message.getJmsRedelivered(){...}

        如果没有,请处理

        如果已重新传送,请检查您是否已经处理

        根据消息

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

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

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

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

        但是对于XA,你有开销

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