spring mybatis atomikos 多库分布式事务demo

        最近有点时间 , 就准备搭个多库事务的例子 , 不过中间碰到一些问题 , 这里记录下来 .


        我的atomikos   版本是 3.7.0 ; Spring4 mybatis3 ;


        碰到问题主要有两类  :  

       

       1 :  缺少依赖jar包  

atomikos-util.jar

transactions.jar

transactions-jta.jar

transactions-jdbc-deprecated.jar

mybatis.jar

mybatis-spring.jar

cglib.2.2.2.jar


jta.jar



       2 :  配置文件编写错误

        开始网上down了个配置 , 如下 :

    <beanid="dataSource"class="com.atomikos.jdbc.SimpleDataSourceBean"
        init-method="init"destroy-method="close">
        <propertyname="uniqueResourceName"value="mysql/main"/>
        <propertyname="xaDataSourceClassName"
            value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
        <propertyname="xaDataSourceProperties"
            value="URL=${jdbc.url.a};user=${jdbc.username.a};password=${jdbc.password.a}"/>
        <propertyname="exclusiveConnectionMode"value="true"/>
        <propertyname="connectionPoolSize"value="10"/>
        <propertyname="validatingQuery">
            <value>SELECT 1</value>
        </property>
    </bean>

         额 ... 这个跑起来是报错的 .........


        ds应该酱紫写 :


<bean name="dataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean"  init-method="init" destroy-method="close">  

   <property name="uniqueResourceName">     

       <value>ds1</value>     

   </property>     

   <property name="xaDataSourceClassName">     

       <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>     

   </property>  

   <property name="xaProperties">     

       <props>     

             <prop key="URL">${ds1.jdbc.url}</prop>     

           <prop key="user">${ds1.jdbc.username}</prop>     

           <prop key="password">${ds1.jdbc.password}</prop>     

       </props>     

   </property>     

  <property name="poolSize"><value>1</value></property>       

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

</bean>


<bean name="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean"  init-method="init" destroy-method="close">  

   <property name="uniqueResourceName">     

       <value>ds2</value>     

   </property>     

   <property name="xaDataSourceClassName">     

       <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>     

   </property>  

   <property name="xaProperties">     

       <props>     

             <prop key="URL">${ds2.jdbc.url}</prop>     

           <prop key="user">${ds2.jdbc.username}</prop>     

           <prop key="password">${ds2.jdbc.password}</prop>     

       </props>     

   </property>     

  <property name="poolSize"><value>1</value></property>       

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

</bean>

然后mysql建两个库 , test1 , test2 , 库里各建一张表 t1 , t2 ;

CREATE TABLE `t1` (

  `c1` int(10) unsigned NOT NULL AUTO_INCREMENT,

  `c2` varchar(100) NOT NULL,

  PRIMARY KEY (`c1`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;


             接下来就是spring和mybatis的配置了 , 一路走下来就没什么难点了 ;


             

<?xml version="1.0" encoding="UTF-8"?>

<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:tx="http://www.springframework.org/schema/tx"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:task="http://www.springframework.org/schema/task"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 

       http://www.springframework.org/schema/context 

       http://www.springframework.org/schema/context/spring-context-3.0.xsd 

       http://www.springframework.org/schema/tx 

       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 

       http://www.springframework.org/schema/aop 

       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

       http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">


    <context:property-placeholder location="classpath:config.properties" />


    <bean id="propertyConfigurer"

          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="locations">

            <list>

                <value>classpath:config.properties</value>

            </list>

        </property>

    </bean>


    <context:annotation-config/>


    <aop:aspectj-autoproxy proxy-target-class="true"/>


    <context:component-scan base-package="my.service"/>


</beans>

注解配置 ↑ .....

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
       default-autowire="byName" default-lazy-init="false">

    <bean name="dataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean"  init-method="init" destroy-method="close">  
       <property name="uniqueResourceName">     
           <value>ds1</value>     
       </property>     
       <property name="xaDataSourceClassName">     
           <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>     
       </property>  
       <property name="xaProperties">     
           <props>     
                 <prop key="URL">${ds1.jdbc.url}</prop>     
               <prop key="user">${ds1.jdbc.username}</prop>     
               <prop key="password">${ds1.jdbc.password}</prop>     
           </props>     
       </property>     
      <property name="poolSize"><value>1</value></property>       
      <property name="maxPoolSize"><value>30</value></property>     
    </bean>
    
    <bean name="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean"  init-method="init" destroy-method="close">  
       <property name="uniqueResourceName">     
           <value>ds2</value>     
       </property>     
       <property name="xaDataSourceClassName">     
           <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>     
       </property>  
       <property name="xaProperties">     
           <props>     
                 <prop key="URL">${ds2.jdbc.url}</prop>     
               <prop key="user">${ds2.jdbc.username}</prop>     
               <prop key="password">${ds2.jdbc.password}</prop>     
           </props>     
       </property>     
      <property name="poolSize"><value>1</value></property>       
      <property name="maxPoolSize"><value>30</value></property>    
    </bean>
       
   <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(* *my.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="*"  propagation="REQUIRED" rollback-for="Exception"  />  
           </tx:attributes>  
       </tx:advice>  
    
</beans>

ds配置 ↑ ..........

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
       default-autowire="byName" default-lazy-init="false">


    <bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="dataSource" ref="dataSource1"/>
        <property name="mapperLocations">
            <list>
                <value>classpath*:*-mapper1.xml</value>
            </list>
        </property>
    </bean>

    <bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="dataSource" ref="dataSource2"/>
        <property name="mapperLocations">
            <list>
                <value>classpath*:*-mapper2.xml</value>
            </list>
        </property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="my.mapper1"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"></property>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="my.mapper2"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"></property>
    </bean>

</beans>

spring-mybatis 集成 ↑ ..........

需要注意的是还需要在classpath下新建一个jta.properties
内容可以参考这个 , 根据实际场景做修改 

# SAMPLE PROPERTIES FILE FOR THE TRANSACTION SERVICE  
# THIS FILE ILLUSTRATES THE DIFFERENT SETTINGS FOR THE TRANSACTION MANAGER  
# UNCOMMENT THE ASSIGNMENTS TO OVERRIDE DEFAULT VALUES;  
  
# Required: factory implementation class of the transaction core.  
# NOTE: there is no default for this, so it MUST be specified!   
#   
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
  
          
# Set base name of file where messages are output   
# (also known as the 'console file').  
#  
com.atomikos.icatch.console_file_name = tm.out
  
# Size limit (in bytes) for the console file;  
# negative means unlimited.  
#  
# com.atomikos.icatch.console_file_limit=-1  
  
# For size-limited console files, this option  
# specifies a number of rotating files to   
# maintain.  
#  
# com.atomikos.icatch.console_file_count=1  
  
# Set the number of log writes between checkpoints  
#  
# com.atomikos.icatch.checkpoint_interval=500  
  
# Set output directory where console file and other files are to be put  
# make sure this directory exists!  
#  
# com.atomikos.icatch.output_dir = ./  
  
# Set directory of log files; make sure this directory exists!  
#  
# com.atomikos.icatch.log_base_dir = ./  
  
# Set base name of log file  
# this name will be  used as the first part of   
# the system-generated log file name  
#  
com.atomikos.icatch.log_base_name = tmlog
  
# Set the max number of active local transactions   
# or -1 for unlimited.  
#  
# com.atomikos.icatch.max_actives = 50  
  
# Set the default timeout (in milliseconds) for local transactions  
#  
# com.atomikos.icatch.default_jta_timeout = 10000  
  
# Set the max timeout (in milliseconds) for local transactions  
#  
# com.atomikos.icatch.max_timeout = 300000  
  
# The globally unique name of this transaction manager process  
# override this value with a globally unique name  
#  
com.atomikos.icatch.tm_unique_name = tm
      
# Do we want to use parallel subtransactions? JTA's default  
# is NO for J2EE compatibility  
#  
# com.atomikos.icatch.serial_jta_transactions=true  
                      
# If you want to do explicit resource registration then  
# you need to set this value to false.  
#  
# com.atomikos.icatch.automatic_resource_registration=true    
      
# Set this to WARN, INFO or DEBUG to control the granularity  
# of output to the console file.  
#  
com.atomikos.icatch.console_log_level=INFO
      
# Do you want transaction logging to be enabled or not?  
# If set to false, then no logging overhead will be done  
# at the risk of losing data after restart or crash.  
#  
# com.atomikos.icatch.enable_logging=true  
  
# Should two-phase commit be done in (multi-)threaded mode or not?  
# Set this to false if you want commits to be ordered according  
# to the order in which resources are added to the transaction.  
#  
# NOTE: threads are reused on JDK 1.5 or higher.   
# For JDK 1.4, thread reuse is enabled as soon as the   
# concurrent backport is in the classpath - see   
# http://mirrors.ibiblio.org/pub/mirrors/maven2/backport-util-concurrent/backport-util-concurrent/  
#  
# com.atomikos.icatch.threaded_2pc=false  
  
# Should shutdown of the VM trigger shutdown of the transaction core too?  
#  
# com.atomikos.icatch.force_shutdown_on_vm_exit=false  

写两个测试用的mapper


@Repository("testMapper1")

public interface TestMapper1 {

   

   int testMethod();


   void insertT1WithException();


   void insertT1WithOutException(String s);

   

}

@Repository("testMapper2")

public interface TestMapper2 {

   

   int testMethod();


   void insertT2WithException();


   void insertT2WithOutException(String s);

   

}

 service ............

@Service

public class TestService {

   @Resource

   private TestMapper1 testMapper1;

   @Resource

   private TestMapper2 testMapper2;

   

   public void test(){

      String s = UUID.randomUUID().toString();


      testMapper1.insertT1WithOutException(s);

//    testMapper1.insertT1WithException();


//    testMapper2.insertT2WithOutException(s);

      testMapper2.insertT2WithException();


   }


}


             然后在testcase里调用 :


             

insertT1WithOutException为正常操作 , 

insertT1WithException则会抛出异常 ,

System.out.println("begin");

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-*.xml");

TestService testService = (TestService) ctx.getBean("testService");

testService.test();

System.out.println("end");

执行结果如下 , 可以看到两个操作都回滚了 ╮(╯▽╰)╭  


DEBUG org.springframework.transaction.jta.JtaTransactionManager Initiating transaction rollback
DEBUG atomikos getCompositeTransaction()  returning instance with id tm0000100023
DEBUG atomikos getCompositeTransaction()  returning instance with id tm0000100023
DEBUG atomikos getCompositeTransaction()  returning instance with id tm0000100023
DEBUG atomikos getCompositeTransaction()  returning instance with id tm0000100023
INFO atomikos XAResource.rollback ( 746D30303030313030303233:746D31 ) on resource ds1 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@4b6690c0
INFO atomikos XAResource.rollback ( 746D30303030313030303233:746D32 ) on resource ds2 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@6b8d96d9
INFO atomikos rollback() done of transaction tm0000100023


 =============================================================================================================

          

         代码传到csdn了 , 不过多了很多无用的jar包 , 大家可以删掉 , 地址 : http://download.csdn.net/detail/ayanami001/9108113 

        

         还有个根据数据库自动生成mapper , xml , 以及service接口的小工具 , 基于ftl , 也分享给大家 ╮(╯▽╰)╭ 


         http://download.csdn.net/detail/ayanami001/9104585

          

=============================================================================================================

 


         =============================================================================================================
         =============================================================================================================
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值