SpringMVC+MyBatis+JMS+JTA(分布式事务)

SpringMVC+MyBatis 相信已经是现在企业开发中常用技术了。
因为一些需求,我们需要集成JMS(我使用的是ActiveMQ),大家应该都知道,MQ也可以认为是一个数据源,数据也是数据源。这种情况下,如果我们在一个方法内操作JMS和数据库,我们就需要保证这个方法执行需要满足原子性。
这也就意味这一个问题,我们要多个数据源在同一个事务中。这里不枚举市面上的所有解决方案,其实atomikos JTA 是一个比较不错分布式事务管理器。
当然如果没有使用到JMS,在需要多数据源(也就是需要连接多个数据库)的情况同样适用。

下面将项目的主要配置贴出来共享:
1、applicationContext.xml


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:amq="http://activemq.apache.org/schema/core"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://activemq.apache.org/schema/core
        http://activemq.apache.org/schema/core/activemq-core-5.13.0.xsd">

     <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

     
     <context:component-scan base-package="com.hvgroup.zhuhai10086.jms">
        
        
        
        
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
     context:component-scan>

    
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:config/config.propertiesvalue>
            list>
        property>
    bean>

    <import resource="classpath:spring/applicationContext-Service.xml" />

beans>  

2、applicationContext-Service.xml


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

    
    
    
    
    
    
    
    

    
















    <bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
        init-method="init" destroy-method="close">
        <property name="uniqueResourceName" value="ds1" />

        <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
        <property name="xaProperties">
            <props>
                <prop key="URL">${jdbc.url}prop>
                <prop key="user">${jdbc.username}prop>
                <prop key="password">${jdbc.password}prop>
            props>
        property>

        <property name="minPoolSize" value="5" />

        <property name="maxPoolSize" value="20" />

        <property name="maxIdleTime" value="60" />
        <property name="testQuery">
            <value>select 1value>
        property>
    bean>


    
    
    
    
    
    

    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        
        <property name="mapperLocations">
            <list>
                
                <value>classpath*:com/hvgroup/zhuhai10086/jms/**/sql/mysql/*Mapper.xml
                value>
            list>
        property>
        <property name="plugins">
            <array>
                
                <bean class="com.github.pagehelper.PageHelper">
                    <property name="properties">
                        <value>
                            offsetAsPageNum=true
                            rowBoundsWithCount=true
                            reasonable=true
                        value>
                    property>
                bean>
            array>
        property>
    bean>

         





    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hvgroup.zhuhai10086.jms.**.mapper" />
        <property name="markerInterface" value="com.hvgroup.zhuhai10086.jms.mapper.SqlMapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    bean>


    <bean id="userTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp" 
            init-method="init" destroy-method="shutdownForce">
        <constructor-arg>
            <props>
                <prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactoryprop>
            props>
        constructor-arg>
    bean>

    <bean id="atomikosTransactionManager"  
          class="com.atomikos.icatch.jta.UserTransactionManager"  
          depends-on="userTransactionService"
          init-method="init" destroy-method="close" >  
        <property name="forceShutdown" value="false"/>
    bean>

    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" >  
        <property name="transactionTimeout" value="300"/>  
    bean>

    
    <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">  
        <property name="transactionManager" ref="atomikosTransactionManager"/>  
        <property name="userTransaction" ref="atomikosUserTransaction"/>  
    bean>


    
    <tx:annotation-driven transaction-manager="jtaTransactionManager" />

beans>

3、ActiveMQ-XA.xml


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:amq="http://activemq.apache.org/schema/core"
    xmlns:jms="http://www.springframework.org/schema/jms"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/jms
        http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
        http://activemq.apache.org/schema/core
        http://activemq.apache.org/schema/core/activemq-core-5.13.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

    
    <amq:redeliveryPolicy id="redeliveryPolicy"
        maximumRedeliveries="6" />

    
    <amq:prefetchPolicy id="prefetchPolicy" queuePrefetch="5" topicPrefetch="5" />

    
    <amq:xaConnectionFactory id="jmsXaConnectionFactory"
        brokerURL="${activemq.brokerURL}" 
        userName="${activemq.username}" 
        password="${activemq.password}"
        redeliveryPolicy="#redeliveryPolicy"
        alwaysSessionAsync="false"
        alwaysSyncSend="true" 
        prefetchPolicy="#prefetchPolicy"/>



    <bean id="amqConnectionFactory"  
          class="com.atomikos.jms.AtomikosConnectionFactoryBean" init-method="init" destroy-method="close">  
        <property name="uniqueResourceName" value="XAactiveMQ"/>  
        <property name="xaConnectionFactory" ref="jmsXaConnectionFactory"/>  
        <property name="poolSize" value="100"/>
    bean>

    

    
    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
        <constructor-arg ref="amqConnectionFactory" />
        
        <property name="pubSubDomain" value="false" />
    bean>

    
    <bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
        <constructor-arg ref="amqConnectionFactory" />
         
        <property name="pubSubDomain" value="true" />
    bean>

    

    

      
    <amq:queue id="queueReceiver2ResponseDestination"  physicalName="test.queue2.response" />

    
    <jms:listener-container
        destination-type="queue" 
        container-type="default" 
        connection-factory="amqConnectionFactory" 
        error-handler="jmsErrorHandler"
        acknowledge="auto">
        <jms:listener destination="xinge.queue.push" ref="xgMessageReceiver"  concurrency="5-100" />
        <jms:listener destination="xinge.queue.push.device.multiple" ref="xgMessageReceiverMultiple"  concurrency="5-100" />
    jms:listener-container>

    
    <jms:listener-container
        destination-type="queue" 
        container-type="default" 
        connection-factory="amqConnectionFactory" 
        transaction-manager="jtaTransactionManager"
        error-handler="jmsErrorHandler"
        acknowledge="transacted">
        <jms:listener destination="xinge.queue.push.invokelog" ref="xgMessageReceiverInvokeLog"  concurrency="5-100" />



    jms:listener-container>

    











    

    <bean id="xingeApp" class="com.tencent.xinge.XingeApp">
        <constructor-arg index="0" value="2100170086"/>
        <constructor-arg index="1" value="2d257b10220bc3849743ffe0e9bd233a"/>
    bean>

beans>  

4、spring-mvc.xml

  
<beans xmlns="http://www.springframework.org/schema/beans"   
       xmlns:aop="http://www.springframework.org/schema/aop"   
       xmlns:context="http://www.springframework.org/schema/context"  
       xmlns:mvc="http://www.springframework.org/schema/mvc"   
       xmlns:tx="http://www.springframework.org/schema/tx"   
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/aop   
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd   
        http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.0.xsd   
        http://www.springframework.org/schema/mvc   
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd   
        http://www.springframework.org/schema/tx   
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">  

    
    <mvc:annotation-driven />

    
    <mvc:resources location="/resources/" mapping="/resources/**"/>

    
    <context:component-scan base-package="com.hvgroup.zhuhai10086.jms" >
        
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>

    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/WEB-INF/views/" />  
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    bean>

beans>  

5、config.properties

jdbc.url=jdbc:mysql://localhost:3306/xgmessage?useUnicode=true&;characterEncoding=utf-8&relaxAutoCommit=true
jdbc.username=root
jdbc.password=123456

activemq.brokerURL=tcp://localhost:61616
activemq.username=admin
activemq.password=admin

6、web.xml


<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:web="http://java.sun.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    <display-name>zhuhai10086-jmsdisplay-name>
    <context-param>
        <param-name>webAppRootKeyparam-name>
        <param-value>zhuhai10086-jmsparam-value>
    context-param>
    
    <context-param>
        <param-name>log4jConfigLocationparam-name>
        <param-value>classpath:log4j/log4j.xmlparam-value>
    context-param>
    
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListenerlistener-class>
    listener>
    <filter>
        <filter-name>characterEncodingfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        <init-param>
            <param-name>encodingparam-name>
            <param-value>UTF-8param-value>
        init-param>
        <init-param>
            <param-name>forceEncodingparam-name>
            <param-value>trueparam-value>
        init-param>
    filter>
    <filter-mapping>
        <filter-name>characterEncodingfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    <context-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>classpath*:spring/applicationContext.xml,classpath*:activemq/ActiveMQ-XA.xml
        param-value>
    context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
    listener>
    <servlet>
        <servlet-name>SpringMVCservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:spring/spring-mvc.xmlparam-value>
        init-param>
        <load-on-startup>1load-on-startup>
    servlet>
    <servlet-mapping>
        <servlet-name>SpringMVCservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>
web-app>

7、把log4j.xml 也贴出来吧,兴许有的同学能用上



<log4j:configuration debug="true" xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d][%p][%13F:%L] %m%n" />
        layout>
    appender>
    <appender name="DEBUG" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="${log4j.logfile.path}" />
        <param name="Encoding" value="UTF-8" />
        <param name="DatePattern" value="'.'yyyy-MM-dd" />
        <param name="ImmediateFlush" value="true" />
        <param name="Append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d][%p] %m%n" />
        layout>
    appender>

    <logger name="java.sql.Connection">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="java.sql.PreparedStatement">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="java.sql.Statement">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="java.sql.ResultSet">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="org.mybatis">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="org.springframework">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>   
    <logger name="org.apache.ibatis">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="org.apache.xbean.spring">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="com.atomikos">
        <level value="ERROR" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>
    <logger name="org.apache.activemq">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>

    <logger name="com.hvgroup">
        <level value="DEBUG"/>
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    logger>

    
    <root>
        <level value="DEBUG"/>
    root>

log4j:configuration>

对需要使用数据库数据源的方法使用 @Transactional 注解即可,在配置上,JMS的事务我们已经在配置文件中指定了。如下代码中指定的 transaction-manager=”jtaTransactionManager”:

    
    <jms:listener-container
        destination-type="queue" 
        container-type="default" 
        connection-factory="amqConnectionFactory" 
        transaction-manager="jtaTransactionManager"
        error-handler="jmsErrorHandler"
        acknowledge="transacted">
        <jms:listener destination="xinge.queue.push.invokelog" ref="xgMessageReceiverInvokeLog"  concurrency="5-100" />
    jms:listener-container>

最后贴上工程代码的结构图:
SpringMVC+MyBatis+JMS+JTA(分布式事务)_第1张图片

声明:本文是我在项目实际业务开发之前搭建的框架,其中如出现一些敏感字,声明不涉及版权问题。
贴出的配置,仅供大家学习。

你可能感兴趣的:(SpringMVC+MyBatis+JMS+JTA(分布式事务))