zoukankan      html  css  js  c++  java
  • spring+mybatis+atomikos 实现JTA事务

    1. 选择哪种transaction manager?
         在单数据源情况下,JDBC,Hibernate,ibatis等自带的 transaction manager已能用于处理事务。
        但当设计多种数据源的事务处理时,上面的transaction manager就没法用了。这个时候可选事务管理组件有:Bitronix,SimpleJTA,Tyrex (dead?), JOTM (used in Jonas),GeronimoTM/Jencks (used in Geronimo),JBossTS (used in JBoss) andAtomikos. 其中Atomikos 被大多数人所推荐。

    2. 最近弄一个框架,使用spring3.0.5+mybatis3.0.5,需要访问多库,要应用分布式事务JTA,这是用atomikos 3.70版本,并把配置做一下记录。

    配置多个数据源
     
    Xml代码 
    <!-- 第一个数据库 -->  
         <bean id="dataSource" class="com.atomikos.jdbc.SimpleDataSourceBean"  
             init-method="init" destroy-method="close">  
             <property name="uniqueResourceName" value="mysql/main" />  
             <property name="xaDataSourceClassName"  
                 value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />  
             <property name="xaDataSourceProperties"  
                 value="URL=${jdbc.url.a};user=${jdbc.username.a};password=${jdbc.password.a}" />  
             <property name="exclusiveConnectionMode" value="true" />  
             <property name="connectionPoolSize" value="10" />  
             <property name="validatingQuery">  
                 <value>SELECT 1</value>  
             </property>  
         </bean>  
         <!-- 第二个数据库 -->  
         <bean id="dataSourceB" class="com.atomikos.jdbc.SimpleDataSourceBean"  
             init-method="init" destroy-method="close">  
             <property name="uniqueResourceName" value="mysql/news" />  
             <property name="xaDataSourceClassName"  
                 value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />  
             <property name="xaDataSourceProperties"  
                 value="URL=${jdbc.url.b};user=${jdbc.username.b};password=${jdbc.password.b}" />  
             <property name="exclusiveConnectionMode" value="true" />  
             <property name="connectionPoolSize" value="10" />  
             <property name="validatingQuery">  
                 <value>SELECT 1</value>  
             </property>  
         </bean>  
    <!-- 第一个数据库 -->
    <bean id="dataSource" class="com.atomikos.jdbc.SimpleDataSourceBean"
    init-method="init" destroy-method="close">
    <property name="uniqueResourceName" value="mysql/main" />
    <property name="xaDataSourceClassName"
    value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
    <property name="xaDataSourceProperties"
    value="URL=${jdbc.url.a};user=${jdbc.username.a};password=${jdbc.password.a}" />
    <property name="exclusiveConnectionMode" value="true" />
    <property name="connectionPoolSize" value="10" />
    <property name="validatingQuery">
    <value>SELECT 1</value>
    </property>
    </bean>
    <!-- 第二个数据库 -->
    <bean id="dataSourceB" class="com.atomikos.jdbc.SimpleDataSourceBean"
    init-method="init" destroy-method="close">
    <property name="uniqueResourceName" value="mysql/news" />
    <property name="xaDataSourceClassName"
    value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
    <property name="xaDataSourceProperties"
    value="URL=${jdbc.url.b};user=${jdbc.username.b};password=${jdbc.password.b}" />
    <property name="exclusiveConnectionMode" value="true" />
    <property name="connectionPoolSize" value="10" />
    <property name="validatingQuery">
    <value>SELECT 1</value>
    </property>
    </bean>
     
     
    配置mybatis的SessionFactory
     
     
    Xml代码 
    <bean id="sqlSessionFactoryB" class="org.mybatis.spring.SqlSessionFactoryBean">  
         <property name="configLocation" value="classpath:mybatis/mybatis-config-b.xml" />  
         <property name="dataSource" ref="dataSourceB" />  
     </bean>  
       
     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
         <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />  
         <property name="dataSource" ref="dataSource" />  
     </bean>  
    <bean id="sqlSessionFactoryB" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="configLocation" value="classpath:mybatis/mybatis-config-b.xml" />
    <property name="dataSource" ref="dataSourceB" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
    <property name="dataSource" ref="dataSource" />
    </bean>
     这里使用的是SessionFactory,不是org.springframework.orm.ibatis.SqlMapClientFactoryBean,在mybatis3中用SqlMapClientFactoryBean汇报com.ibatis.common.xml.NodeletException 异常。
     
    configLocation 对应的mybatis配置,跟平时配置一样。
    Xml代码 
    <?xml version="1.0" encoding="UTF-8" ?>  
     <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  
     <configuration>  
         <typeAliases>  
             <typeAlias alias="User"  type="com.lantii.domain.User"/>  
         </typeAliases>  
         <mappers>  
             <mapper resource="com/lantii/dao/UserMapper.xml" />  
         </mappers>  
     </configuration>    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    <typeAliases>
    <typeAlias alias="User"  type="com.lantii.domain.User"/>
    </typeAliases>
    <mappers>
    <mapper resource="com/lantii/dao/UserMapper.xml" />
    </mappers>
    </configuration>

     事务这块用spring管理atomikos
    Xml代码 
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"  
             init-method="init" destroy-method="close">  
             <property name="forceShutdown">  
                 <value>true</value>  
             </property>  
         </bean>  
       
         <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">  
             <property name="transactionTimeout" value="300" />  
         </bean>  
       
         <bean id="springTransactionManager"  
             class="org.springframework.transaction.jta.JtaTransactionManager">  
             <property name="transactionManager">  
                 <ref bean="atomikosTransactionManager" />  
             </property>  
             <property name="userTransaction">  
                 <ref bean="atomikosUserTransaction" />  
             </property>  
         </bean>  
       
         <aop:aspectj-autoproxy />  
       
         <aop:config  proxy-target-class="true">  
             <aop:advisor pointcut="execution(* *com.lantii.service..*(..))"  
                 advice-ref="txAdvice" />  
         </aop:config>  
       
         <tx:advice id="txAdvice" transaction-manager="springTransactionManager">  
             <tx:attributes>  
                 <tx:method name="get*"  propagation="REQUIRED"  read-only="true" />  
                 <tx:method name="find*"  propagation="REQUIRED"  read-only="true" />  
                 <tx:method name="has*"  propagation="REQUIRED"  read-only="true" />  
                 <tx:method name="locate*"  propagation="REQUIRED"  read-only="true" />  
                 <tx:method name="*"  propagation="REQUIRED" rollback-for="Exception"  />  
             </tx:attributes>  
         </tx:advice>  
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
    init-method="init" destroy-method="close">
    <property name="forceShutdown">
    <value>true</value>
    </property>
    </bean>

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

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

    <aop:aspectj-autoproxy />

    <aop:config  proxy-target-class="true">
    <aop:advisor pointcut="execution(* *com.lantii.service..*(..))"
    advice-ref="txAdvice" />
    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="springTransactionManager">
    <tx:attributes>
    <tx:method name="get*"  propagation="REQUIRED"  read-only="true" />
    <tx:method name="find*"  propagation="REQUIRED"  read-only="true" />
    <tx:method name="has*"  propagation="REQUIRED"  read-only="true" />
    <tx:method name="locate*"  propagation="REQUIRED"  read-only="true" />
    <tx:method name="*"  propagation="REQUIRED" rollback-for="Exception"  />
    </tx:attributes>
    </tx:advice>
     
    Mapper的管理及注入
    Xml代码 
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">  
             <property name="sqlSessionFactory" ref="sqlSessionFactory" />  
             <property name="mapperInterface" value="com.lantii.dao.UserMapper" />  
         </bean>  
            
         <bean id="roleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">  
             <property name="sqlSessionFactory" ref="sqlSessionFactoryB" />  
             <property name="mapperInterface" value="com.lantii.dao.RoleMapper" />  
         </bean>  
       
         <bean id="userService" class="com.lantii.service.UserServiceImpl">  
             <property name="userMapper" ref="userMapper" />  
             <property name="roleMapper" ref="roleMapper" />  
         </bean>  
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    <property name="mapperInterface" value="com.lantii.dao.UserMapper" />
    </bean>

    <bean id="roleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="sqlSessionFactory" ref="sqlSessionFactoryB" />
    <property name="mapperInterface" value="com.lantii.dao.RoleMapper" />
    </bean>

    <bean id="userService" class="com.lantii.service.UserServiceImpl">
    <property name="userMapper" ref="userMapper" />
    <property name="roleMapper" ref="roleMapper" />
    </bean>  
    atomikos的配置jta.properties,该文件放在应用classpath下面
    Java代码 
    com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory   
     com.atomikos.icatch.console_file_name = tm.out   
     com.atomikos.icatch.log_base_name = tmlog   
     com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm   
     com.atomikos.icatch.console_log_level=WARN  
    com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
    com.atomikos.icatch.console_file_name = tm.out
    com.atomikos.icatch.log_base_name = tmlog
    com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
    com.atomikos.icatch.console_log_level=WARN
      
    这几基本配置完毕,需要jar包
    atomikos-util.jar
    transactions.jar
    transactions-jta.jar
    transactions-jdbc-deprecated.jar
    mybatis.jar
    mybatis-spring.jar
    cglib.2.2.2.jar
    spring的jar包
     
    在Service中,调用事务的方法不能try。。。catch事务的方法,否者不能回滚
    如下带面就会出现不会滚问题
    Java代码 
    try{   
                     userMapper.addUser(user);   
                     roleMapper.addRole(role);   
                 }catch(Exception){   
                        
                 }  

    3. 使用atomikos作分布式事务,连接池超时问题
     2012-11-15

    mysql会自动断开超过60秒的连接,而atomikos连接池没有检测机制去保持空闲的连接
    造成连接池的连接超时掉了,以下是日志内容
    com.mysql.jdbc.jdbc2.optional.MysqlXAException: Communications link failure


    The last packet successfully received from the server was 157,969 milliseconds ago.  The last packet sent successfully to the server was 3 milliseconds ago.
    at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.mapXAExceptionFromSQLException(MysqlXAConnection.java:604)
    at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.dispatchCommand(MysqlXAConnection.java:583)
    at com.mysql.jdbc.jdbc2.optional.MysqlXAConnection.start(MysqlXAConnection.java:523)
    at com.atomikos.datasource.xa.XAResourceTransaction.resume(XAResourceTransaction.java:498)
    at com.atomikos.datasource.xa.session.BranchEnlistedStateHandler.<init>(BranchEnlistedStateHandler.java:59)
    at com.atomikos.datasource.xa.session.NotInBranchStateHandler.checkEnlistBeforeUse(NotInBranchStateHandler.java:65)
    at com.atomikos.datasource.xa.session.TransactionContext.checkEnlistBeforeUse(TransactionContext.java:88)
    at com.atomikos.datasource.xa.session.SessionHandleState.notifyBeforeUse(SessionHandleState.java:179)
    at com.atomikos.jdbc.AtomikosConnectionProxy.enlist(AtomikosConnectionProxy.java:208)
    at com.atomikos.jdbc.AtomikosConnectionProxy.invoke(AtomikosConnectionProxy.java:142)
    google下看到几个说修改mysql连接超时设置,我觉得mysql连接超时配置是不建议修改的,有没有更好的方式解决呢

    ........................................................
  • 相关阅读:
    linux
    JAVA——遍历
    linux基础命令
    Java的反射和代理以及注解
    web 前端遇到的问题
    JTopo 使用
    阿里云服务器linux(cenos)下 jdk、tomcat的安装配置
    笔记--数据库总结
    0.01的区别
    犹豫——辛苦——坚持——收获 (2019北航软工培训总结)
  • 原文地址:https://www.cnblogs.com/huapox/p/3516401.html
Copyright © 2011-2022 走看看