spring activeMQ 整合(四): JMS 事務管理

1.爲什麼要用事務?

       消息事務是在生產者producer到broker或broker到consumer過程中同一個session中發生的,保證幾條消息在發送過程中的原子性。
       可以在connection的createSession方法中指定一個布爾值開啓,如果消息確認機制是事務確認,那麼在發送message的過程中session就會開啓事務(實際上broker的),不用用戶顯示調用 beginTransaction,這時所有通過session發送的消息都被緩存下來,用戶調用session.commit時會發送所有消息,當發送出現異常時用戶可以調用rollback進行回滾操作,只有在開啓事務狀態下有效。
 

爲什麼commit之後,不會有持久的消息重新傳送呢?

       原因在於commit操作會自動將爲簽收確認的消息進行簽收確認,如果是當前接收但未簽收確認的消息,都會被確認處理。因而在commit之後不會有持久化的消息出現。


2.activeMQ支持的事務:

ActiveMQ有支持兩種事務,

  • JMS transactions - the commit() / rollback() methods on a Session (which is like doing commit() / rollback() on a JDBC connection)
  • XA Transactions - where the XASession acts as an XAResource by communicating with the Message Broker, rather like a JDBC Connection takes place in an XA transaction by communicating with the database.

在支持事務的session中,producer發送message時在message中帶有transaction ID。broker收到message後判斷是否有transaction ID,如果有就把message保存在transaction store中,等待commit或者rollback消息。所以ActiveMq的事務是針對broker而不是producer的,不管session是否commit,broker都會收到message。

如果producer發送模式選擇了persistent,那麼message過期後會進入死亡隊列。在message進入死亡隊列之前,ActiveMQ會刪除message中的transaction ID,這樣過期的message就不在事務中了,不會保存在transaction store中,會直接進入死亡隊列。具體刪除transaction ID的地方是在:org.apache.activemq.util.BrokerSupport的doResend,將transaction ID保存在了originalTransactionID中,刪除了transaction ID。

       在下面的介紹中我用的是JMS transactions.

JMS transactions事務的配置:

      ①建立JMS事務,並引入關聯鏈接事務。

         ②.設置一個jmsTamplat,並關聯監聽容器。

[html] view plain copy
  1. <!-- jms事務 -->  
  2.     <bean id="jmsTransactionManager"  
  3.         class="org.springframework.jms.connection.JmsTransactionManager">  
  4.         <property name="connectionFactory" ref="connectionFactory" />  
  5.     </bean>  
  6.     <tx:annotation-driven transaction-manager="jmsTransactionManager" />  
  7.   
  8.   
  9. <!-- 消息監聽容器 消息接收監聽器用於異步接收消息 -->  
  10.     <bean id="jmsContainerOne" class="org.springframework.jms.listener.DefaultMessageListenerContainer">  
  11.         <property name="connectionFactory" ref="connectionFactory" />  
  12.         <property name="destination" ref="destinationOne" />  
  13.         <property name="messageListener" ref="consumerMessageListenerOfOne" />  
  14.         <!-- <property name="sessionTransacted" value="true"/> -->  <!-- 給listener添加事務,只負責接收消息的回滾 (有了transactionManager就不用這個了,這個功能不全) 設置後好像並沒有起作用 不知道爲啥 -->  
  15.         <!-- <property name="transactionManager" ref="jtaTransactionManager"/> --> <!-- 接收消息和數據庫訪問處於同一事務中 jta -->  
  16.         <property name="transactionManager" ref="jmsTransactionManager" /> <!--jms事務 -->  
  17.         <property name="sessionAcknowledgeMode" value="4"></property>   <!-- 應答模式是 INDIVIDUAL_ACKNOWLEDGE http://blog.csdn.net/yueding_h/article/details/54944254 -->  
  18.         <!-- ActiveMQ:設置多個並行的消費者 -->  
  19.         <property name="concurrency" value="2-3" />  
  20.     </bean>  

上面配置文件配置完成後,在接收着那邊接受消息失敗後,進行事務回滾。
[html] view plain copy
  1. session.rollback();  
   具體實現:
[html] view plain copy
  1. public void onMessage(Message message, Session session) {     
  2.       TextMessage textMsg = (TextMessage) message;  
  3.         try {  
  4.                 System.out.println(1);  
  5.                 String endStr = textMsg.getText();  
  6.                 Integer endInt = Integer.parseInt(endStr);  
  7.                 System.out.println("消息:==="+endInt);  
  8.                 //只要被確認後   就會出隊,接受失敗沒有確認成功,會在原隊列裏面  
  9.                     textMsg.acknowledge();  
  10.   
  11.         } catch (Exception e) {    
  12.             try {  
  13.                 session.rollback();  
  14.                 System.out.println("測試回滾");  
  15.                                      e.printStackTrace();  
  16.                              System.out.println("異常信息是:===:" + e.getMessage());  
  17.                   }  
  18.     }  
  這就介紹完了。
  另外,activeMQ還有一種JtaTransactionManager 事務控制。
  事務控制: (這裏讓接收消息和數據庫訪問處於同一事務中)我們就可以配置一個外部的事務管理同時配置一個支持外部事務管理的消息監聽容器(如DefaultMessageListenerContainer) 。要配置這樣一個參與分佈式事務管理的消息監聽容器,我們可以配置一個JtaTransactionManager,當然底層的JMS ConnectionFactory需要能夠支持分佈式事務管理, 並正確地註冊我們的JtaTransactionManager。這樣消息監聽器進行消息接收和對應的數據庫訪問就會處於同一數據庫控制下,當消息接收失敗或數據庫訪問失敗都會進行事務回滾操作。 
   這種事務控制,我在配置的時候,失敗了,所以選用了JMS事務控制。
   待我詳細瞭解JtaTransactionManager 後,再說吧。

原文地址:http://blog.csdn.net/dly1580854879/article/details/68945997
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章