Spring整合JMS(四)——事務管理

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

在Java EE環境中,ConnectionFactory會池化Connection和Session,這樣這些資源將會在整個事務中被有效地重複利用。在一個獨立的環境中,使用Spring的SingleConnectionFactory時全部的事務將公用一個Connection,可是每一個事務將保留本身獨立的Session。數據庫

JmsTemplate能夠利用JtaTransactionManager和可以進行分佈式的 JMS ConnectionFactory處理分佈式事務。session

       在Spring整合JMS的應用中,若是咱們要進行本地的事務管理的話很是簡單,只須要在定義對應的消息監聽容器時指定其sessionTransacted屬性爲true,如:分佈式

  1. <bean id="jmsContainer"  
  2.     class="org.springframework.jms.listener.DefaultMessageListenerContainer">  
  3.     <property name="connectionFactory" ref="connectionFactory" />  
  4.     <property name="destination" ref="queueDestination" />  
  5.     <property name="messageListener" ref="consumerMessageListener" />  
  6.     <property name="sessionTransacted" value="true"/>  
  7. </bean>  

 

  1. 該屬性值默認爲false,這樣JMS在進行消息監聽的時候就會進行事務控制,當在接收消息時監聽器執行失敗時JMS就會對接收到的消息進行回滾,對於SessionAwareMessageListener在接收到消息後發送一個返回消息時也處於同一事務下,可是對於其餘操做如數據庫訪問等將不屬於該事務控制。
  2. 這裏咱們能夠來作一個這樣的測試:咱們如上配置監聽在queueDestination的消息監聽容器的sessionTransacted屬性爲true,而後把咱們前面提到的消息監聽器ConsumerMessageListener改爲這樣:測試

  3. public class ConsumerMessageListener implements MessageListener {  
  4.    
  5.     public void onMessage(Message message) {  
  6.             //這裏咱們知道生產者發送的就是一個純文本消息,因此這裏能夠直接進行強制轉換,或者直接把onMessage方法的參數改爲Message的子類TextMessage  
  7.             TextMessage textMsg = (TextMessage) message;  
  8.             System.out.println("接收到一個純文本消息。");  
  9.             try {  
  10.                 System.out.println("消息內容是:" + textMsg.getText());  
  11.                 if (1 == 1) {  
  12.                     throw new RuntimeException("Error");  
  13.                 }  
  14.             } catch (JMSException e) {  
  15.                 e.printStackTrace();  
  16.             }  
  17.     }  
  18.    

咱們能夠看到在上述代碼中咱們的ConsumerMessageListener在進行消息接收的時候拋出了一個RuntimeException,根據咱們上面說的,由於咱們已經在對應的監聽容器上定義了其sessionTransacted屬性爲true,因此當這裏拋出異常的時候JMS將對接收到的消息進行回滾,即下次進行消息接收的時候該消息仍然可以被接收到。爲了驗證這一點,咱們先執行一遍測試代碼,往queueDestination發送一個文本消息,這個時候ConsumerMessageListener在進行接收的時候將會拋出一個RuntimeException,已經接收到的純文本消息將進行回滾;接着咱們去掉上面代碼中拋出異常的語句,即ConsumerMessageListener可以正常的進行消息接收,這個時候咱們再運行一次測試代碼,往ConsumerMessageListener監聽的queueDestination發送一條消息。若是以前在接手時拋出了異常的那條消息已經回滾了的話,那麼這個時候將可以接收到兩條消息,控制檯將輸出接收到的兩條消息的內容。spa

 若是想接收消息和數據庫訪問處於同一事務中,那麼咱們就能夠配置一個外部的事務管理同時配置一個支持外部事務管理的消息監聽容器(如DefaultMessageListenerContainer)。要配置這樣一個參與分佈式事務管理的消息監聽容器,咱們能夠配置一個JtaTransactionManager,固然底層的JMS ConnectionFactory須要可以支持分佈式事務管理,並正確地註冊咱們的JtaTransactionManager。這樣消息監聽器進行消息接收和對應的數據庫訪問就會處於同一數據庫控制下,當消息接收失敗或數據庫訪問失敗都會進行事務回滾操做。線程

配置以下:blog

  1. <bean id="jmsContainer"  
  2.     class="org.springframework.jms.listener.DefaultMessageListenerContainer">  
  3.     <property name="connectionFactory" ref="connectionFactory" />  
  4.     <property name="destination" ref="queueDestination" />  
  5.     <property name="messageListener" ref="consumerMessageListener" />  
  6.     <property name="transactionManager" ref="jtaTransactionManager"/>  
  7. </bean>  
  8.   
  9. <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>  

當給消息監聽容器指定了transactionManager時,消息監聽容器將忽略sessionTransacted的值。事務

JMS進行消息接收拋出異常時咱們的數據庫也會回滾資源

 

原文:http://elim.iteye.com/blog/1983532

相關文章
相關標籤/搜索