spring jms transaction manager

Spring integrates JMS (four) - transaction management

    blog classification: Spring Spring

JMS transaction sessionTransactedJtaTransactionManager


Spring provides a JmsTransactionManager for transaction management of the JMS ConnectionFactory. This will allow JMS applications to take advantage of Spring's transaction management features. JmsTransactionManager binds a ConnectionFactory/Session pair from the specified ConnectionFactory to the thread when performing local resource transaction management. JmsTemplate will automatically detect such transactional resources and act on them accordingly.

In a Java EE environment, ConnectionFactory pools Connections and Sessions so that these resources are effectively reused throughout the transaction. In an independent environment, when using Spring's SingleConnectionFactory, all transactions will share a Connection, but each transaction will keep its own independent Session.

JmsTemplate can handle distributed transactions using JtaTransactionManager and distributed JMS ConnectionFactory.

       In the application of Spring integrated JMS, if we want to perform local transaction management, it is very simple. We only need to specify the sessionTransacted attribute as true when defining the corresponding message monitoring container, such as:


Xml code Collection code

    <bean id="jmsContainer" 
















    public class ConsumerMessageListener implements MessageListener { 
      
        public void onMessage(Message message) { 
                //Here we know that what the producer sends is a plain text message, so we can directly cast it here, or directly change the parameters of the onMessage method to a subclass of Message TextMessage 
                TextMessage textMsg = (TextMessage) message; 
                System.out.println("A plain text message was received."); 
                try { 
                    System.out.println("The message content is: " + textMsg.getText()); 
                    if ( 1 == 1) { 
                        throw new RuntimeException("Error"); 
                    } 
                } catch (JMSException e) { 
                    e.printStackTrace();   
                } 
        } 
      
    } 

       

We can see in the above code that our ConsumerMessageListener threw a RuntimeException when receiving a message. According to what we said above, because we have defined its sessionTransacted property as true on the corresponding listening container, so when here When an exception is thrown, JMS will roll back the received message, that is, the message can still be received the next time the message is received. In order to verify this, we first execute the test code and send a text message to the queueDestination. At this time, the ConsumerMessageListener will throw a RuntimeException when receiving, and the received plain text message will be rolled back; then we remove the above The exception is thrown in the code, that is, the ConsumerMessageListener can receive messages normally. At this time, we run the test code again and send a message to the queueDestination monitored by the ConsumerMessageListener. If the message that threw an exception before taking over has been rolled back, then two messages will be received at this time, and the console will output the contents of the two received messages. Friends who are interested in the specific results can verify it for themselves.

       If we want to receive messages and database access in the same transaction, then we can configure an external transaction management and configure a message listener container (such as DefaultMessageListenerContainer) that supports external transaction management. To configure such a message monitoring container that participates in distributed transaction management, we can configure a JtaTransactionManager. Of course, the underlying JMS ConnectionFactory needs to be able to support distributed transaction management and correctly register our JtaTransactionManager. In this way, the message reception and the corresponding database access by the message listener will be under the control of the same database, and the transaction rollback operation will be performed when the message reception fails or the database access fails.











     


       







  





     


     


 








    public class ConsumerMessageListener implements MessageListener { 
      
        @Autowired 
        private TestDao testDao; 
         
        private int count = 0; 
         
        public void onMessage(Message message) { 
                //Here we know that the producer sends a plain text message, so we can directly cast it here, or Change the parameter of the onMessage method directly to a subclass of Message TextMessage 
                TextMessage textMsg = (TextMessage) message; 
                System.out.println(new Date().toLocaleString() + "Received a plain text message."); 
                try { 
                    String text = textMsg.getText(); 
                    System.out.println("The content of the message is: " + text); 
                    System.out.println("The current value of count is: " + count); 
                    testDao.insert(text + count); 
                    if (count == 0) { 
                        count ++; 
                        throw new RuntimeException("Error! 出错啦!"); 
                    } 
                } catch (JMSException e) { 
                    e.printStackTrace(); 
                } 
        } 
      
    } 



       We can see that in ConsumerMessageListener we define an instance variable count, whose initial value is 0; in onMessage, we can see that we call the insert method of testDao with the received message content as a parameter; when the count value is 0, that is, when the first message is received, the value of count will be incremented by 1, and a runtime exception will be thrown at the same time. Then what we want to test here is that testDao has inserted the relevant content into the database when receiving the first time, and then an exception is thrown in onMessage and the count is incremented by 1. Our expected result should be that the database is rolled back at this time. At the same time, JMS also rolls back, so that JMS will continue to try to receive the message. At this time, the insert method of testDao will also be called to insert the content into the database, and then the count is no longer 0, so the exception will not be thrown at this time, and the JMS will succeed. After receiving the message, testDao also successfully inserted the message content into the database. To prove this expectation, in addition to looking at the data inserted in the database, we can also look at the output of the console. Under normal circumstances, the console will output the content of the received message twice, and the count is 0 for the first time and 1 for the second time. .

       TestDao is an interface, and TestDaoImpl implements the insert method as follows:


Java code Collection code

    @Transactional(readOnly=false) 
    public void insert(final String name) { 
         
        jdbcTemplate.update("insert into test(name) values(?)" , name); 
     
    } 

      

Here we use Weblogic that supports JtaTransactionManager for testing. Because it is a Web container, we define a Controller here to send messages. The specific code is as follows:


Java code Collection code

    @Controller 
    @RequestMapping("test") 
    public class TestController { 
      
        @Autowired 
        @Qualifier("queueDestination") 
        private Destination destination; 
         
        @Autowired 
        private ProducerService producerService; 
         
        @RequestMapping("first") 
        public String first() { 
            producerService.sendMessage(destination, "Hello, now is: " + new Date( ).toLocaleString()); 
            return "/test/first"; 
        } 
         
    } 

     

The next step is to enable the Weblogic server, enter its console, define a JNDI data source named "jdbc/mysql", and then deploy the project to the Weblogic server and start it. Next, we can access /test/first.do to access the above first method. After that, the console will output the following information:



        we can see that when the count is 0, it is received once, and then an exception is thrown, and then the count is 1 and received again, which means that after the exception is thrown when the count is 0, our JMS has been rolled back, so has our database been rolled back? Next, let's look at the contents of the database:



        we can see that there is only one record in the database table, and the last digit indicates that the value of count is 1, which means that our database is also rolled back when an exception is thrown when JMS receives a message. . That's it for the use of JtaTransactionManager for distributed transaction management. Interested friends can try it out for themselves.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326990451&siteId=291194637