學習ActiveMQ(七):JMS消息的事務管理


Spring提供了一個JmsTransactionManager用於對JMS ConnectionFactory做事務管理。這將允許JMS應用利用Spring的事務管理特性。JmsTransactionManager在執行本地資源事務管理時將從指定的ConnectionFactory綁定一個ConnectionFactory/Session這樣的配對到線程中。JmsTemplate會自動檢測這樣的事務資源,並對它們進行相應操作。 

在Spring整合JMS的應用中,如果我們要進行本地的事務管理的話非常簡單,只需要在定義對應的消息監聽容器時指定其sessionTransacted屬性為true。

xml: 增加<property name="sessionTransacted" value="true"/>

<!--配置 消息監聽容器-->
    <bean id="jmsContainer" class=" org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="queueDestination"/>
        <property name="messageListener" ref="consumerMessageListener"/>
        <!--應答模式是 INDIVIDUAL_ACKNOWLEDGE-->
        <!--AUTO_ACKNOWLEDGE = 1    自動確認
        CLIENT_ACKNOWLEDGE = 2    客戶端手動確認
        DUPS_OK_ACKNOWLEDGE = 3    自動批量確認
        SESSION_TRANSACTED = 0    事務提交並確認
        INDIVIDUAL_ACKNOWLEDGE = 4    單條消息確認-->
        <property name="sessionAcknowledgeMode" value="4"/>
        <!--對消息開啟事務模式-->
        <property name="sessionTransacted" value="true"/>
    </bean>

 監聽器加入session.rollback();消息進行回滾重傳(上一篇中因為還沒有學習回滾,所以用的session.recover()實現的重發,現在就可以使用事務rollback()方法實現了)

回滾的過程是消息先出列,然后重發,默認6次,超過次數后進入到死亡隊列,(配置持久化數據庫的時候,並持久化到數據庫一條數據);

回滾肯定是開啟了事務的情況下,那么沒有開啟事務的情況呢?消息沒有確認的情況,消息會停在消息隊列中,等待着再次被監聽,除非調用session.recover()方法,效果和開啟事務並回滾一樣會進入死亡隊列。

   session.rollback();//手動的調用此方法進行回滾,拋出異常時實際上事務開啟后會自動進行回滾的。

調用commit()方法進行提交:值得說的是,在事務模式下,在接收消息沒有確認的情況也會出列。完成消息。

 session.commit();

也就是說,開啟事務后消息永遠不會出現停留在隊列的情況,消息會回滾重發,最后到死亡隊列中,而不開啟事務的情況,只要不使用session.recover();消息會停留在隊列中,不會重發,直至被確認出列。如果調用了recover就和回滾重發一樣了。

我們在實際業務中,接收消息操作和數據庫操作要在一起進行那么該怎么控制事務呢?

Spring里,如果同時存在JMS操作和DB操作,大概也就三種方式:

1.沒有使用JTA。JMS不在事務中,DB操作在事務中   

     a,消息處理

     b,開始數據庫事務

     c,數據庫操作

     d,數據庫提交

         成功:結束

         失敗:回到b重試

這種方式事務沒有集成,靠的純粹是我們程序的控制,如果最終數據庫提交都沒成功的話,可以記下log,再人工去糾正數據。例子里把數據庫操作放在了更重要的位置,其實也可以倒過來,讓數據庫操作先完成,只好在做jms操作,看業務需求了:

     a,開始數據庫事務

     b,數據庫操作

     c,數據庫提交

     d,消息處理

         成功:結束

         失敗:回到d重試

我們只要把spring配置改成

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
...
<!-- This is important... -->
<property name="sessionTransacted" value="false" />
</bean> 
再加上自己程序控制就好了。

2.如果沒有使用JTA,對於上面的配置如果把屬性 sessionTransacted 設成true的話,就產生了第二種方式,過程:

    a,開始jms事務

    b,開始數據庫事務

    c,數據庫和jms操作

    d,提交數據庫操作

    e,提交jms操作

a,b的順序不肯定,不過對程序沒影響,但是d,e的順序是確定的。在Spring里,數據庫會在spring的commit方法里提交,而JMS會在afterCommit方法里提交。如果數據庫失敗,JMS當然也就回滾了,但是如果數據庫成功而JMS失敗,就產生了數據不一致,就要加上其它措施。而且這里還有一個致命缺點,就是某些情況下即使JMS失敗(比如JMS服務器down了),Spring也不會拋出異常,程序外部以為一切正常,而事實上以產生了不一致問題,而且很難發現。

3.如果使用了JTA那么把屬性 sessionTransacted 設成true的話,

JMS和數據庫操作就在同一個事務里了,沒什么好說,最安全的方式,但是效率很低。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM