基于spring,Atomikos,mybatis的分布式动态数据源JTA实现

阅读更多

本文的几个关键词,分布式数据源,数据源的动态寻找,分布式事务JTA实现。
     对于一些较大规模的应用,单个数据源是无法支撑起庞大的用户量,需要引入多数据源,水平层面进行分库分表,降低单个DB的负载。接下来,我们程序里里面需 要管理不同数据源之前的程序调用,保证功能是WORK的。另外,跨库就意味着之前单DB的事务就失效了,所以J2EE提出了JTA,分布式的事务管理,往 简单了说,就是2步提交(two phase),比单步提交更苛刻。实际上他有两个容器来管理,一个是资源管理器,一个是事务管理。小伙伴们可以发现,这是一个环环相扣的过程。想解决一个 问题,你就得解决这几个相关的问题。以下代码,我也是参考了前辈们的思想,进行了改造。

    第一步:XA数据源定义
     选定义一个抽象的父类源,这样子类可以直接继承

  
 1  
 2        < bean  id ="abstractXADataSource"  class ="com.atomikos.jdbc.AtomikosDataSourceBean"  init-method ="init"
 3               destroy-method ="close"  abstract ="true" >
 4           < property  name ="xaDataSourceClassName"  value ="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
 5           < property  name ="poolSize"  value ="10"  />
 6           < property  name ="minPoolSize"  value ="10" />
 7           < property  name ="maxPoolSize"  value ="30" />
 8           < property  name ="borrowConnectionTimeout"  value ="60" />
 9           < property  name ="reapTimeout"  value ="20" />
10          
11           < property  name ="maxIdleTime"  value ="60" />
12           < property  name ="maintenanceInterval"  value ="60"  />
13           < property  name ="loginTimeout"  value ="60" />
14           < property  name ="logWriter"  value ="60" />
15           < property  name ="testQuery" >
16               < value > select 1 value >
17           property >
18          
19       bean >
20 
   A源
     
 1 
 2       < bean  id ="dataSource_a"  parent ="abstractXADataSource" >
 3      
 4           < property  name ="uniqueResourceName"  value ="mysql/sitestone"  />
 5           < property  name ="xaDataSourceClassName"
 6              value ="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"  />
 7           < property  name ="xaProperties" >
 8               < props >
 9                   < prop  key ="URL" > ${jdbc.url.spider} prop >
10                   < prop  key ="user" > ${jdbc.username} prop >
11                   < prop  key ="password" > ${jdbc.password} prop >
12               props >
13           property >
14       bean >
   
B   源

   
 1 
 2       < bean  id ="dataSource_b"  parent ="abstractXADataSource" >
 3 
 4           < property  name ="uniqueResourceName"  value ="mysql/sitesttwo"  />
 5           < property  name ="xaDataSourceClassName"
 6              value ="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"  />
 7           < property  name ="xaProperties" >
 8               < props >
 9                  < prop  key ="URL" > ${jdbc_tb.url.spider} prop >
10                   < prop  key ="user" > ${jdbc_tb.username} prop >
11                   < prop  key ="password" > ${jdbc_tb.password} prop >
12               props >
13           property >
14       bean >

基于SPRING的AbstractRoutingDataSource动态数据路由定义
1     < bean  name ="dynamicDatasource"  class ="com.***.spring.datasource.CustomerDatasource" >
2           < property  name ="targetDataSources" >
3               < map >
4                   < entry  key ="ds_1"  value-ref ="dataSource_a" />
5                   < entry  key ="ds_2"  value-ref ="dataSource_b" />
6               map >
7           property >
8           < property  name ="defaultTargetDataSource"  ref ="dataSource_a"      />
9       bean >

我这里是使用MYBATIS来进行ORM映射,配置如下

 1   < bean  id ="sqlSessionFactorya"  class ="org.mybatis.spring.SqlSessionFactoryBean" >
 2           < property  name ="dataSource"  ref ="dataSource_a" />
 3            < property  name ="typeAliasesPackage"  value ="com.****.spring.dschange.bean"  />
 4             
 5           < property  name ="mapperLocations" >
 6               < list >
 7                    
 8                   < value > classpath:com/***/spring/dschange/mapper/ShopMapper.xml value >
 9               list >
10           property >
11       bean >
12       < bean  id ="sqlSessionFactoryb"  class ="org.mybatis.spring.SqlSessionFactoryBean" >
13           < property  name ="dataSource"  ref ="dataSource_b" />
14            < property  name ="typeAliasesPackage"  value ="com.****.spring.dschange.bean"  />
15              
16           < property  name ="mapperLocations" >
17               < list >
18                    
19                   < value > classpath:com/***/spring/dschange/mapper/ShopMapper.xml value >
20               list >
21           property >
22       bean >

接下来,一个比较关键的地方是对MYBATIS的CustomSqlSessionTemplate的重写,主要是引入动态数据源sqlSessionFactory。针对不同的数据库,调用其对应的会话工厂,这对JTA是否启用,比较重要。

 1   @Override
 2       public  SqlSessionFactory getSqlSessionFactory() {
 3   
 4          SqlSessionFactory targetSqlSessionFactory  =  targetSqlSessionFactorys.get(DataSourceKeyHolder.getDataSourceKey());
 5           if  (targetSqlSessionFactory  !=  null ) {
 6               return  targetSqlSessionFactory;
 7          }  else  if  (defaultTargetSqlSessionFactory  !=  null ) {
 8               return  defaultTargetSqlSessionFactory;
 9          }  else  {
10              Assert.notNull(targetSqlSessionFactorys,  " Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required " );
11              Assert.notNull(defaultTargetSqlSessionFactory,  " Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required " );
12          }
13           return  this .sqlSessionFactory;
14      }
XML配置
 1  
 2       < bean  id ="sqlSessionTemplate"  class ="com.amos.spring.mybatis.CustomSqlSessionTemplate"  scope ="prototype" >
 3           < constructor-arg  ref ="sqlSessionFactorya"  />
 4           < property  name ="targetSqlSessionFactorys" >
 5               < map >      
 6                   < entry  value-ref ="sqlSessionFactorya"  key ="ds_1" />
 7                   < entry  value-ref ="sqlSessionFactoryb"  key ="ds_2" />
 8               map >  
 9           property >
10       bean >

扫描配置

1   < bean  id ="mapperScannerConfigurer"  class ="org.mybatis.spring.mapper.MapperScannerConfigurer" >
 1      
 2       < bean  id ="atomikosTransactionManager"  class ="com.atomikos.icatch.jta.UserTransactionManager"
 3          init-method ="init"  destroy-method ="close" >
 4           < property  name ="forceShutdown" >
 5               < value > true value >
 6           property >
 7       bean >
 8   
 9       < bean  id ="atomikosUserTransaction"  class ="com.atomikos.icatch.jta.UserTransactionImp" >
10           < property  name ="transactionTimeout"  value ="300"  />
11       bean >
12   
13       < bean  id ="springTransactionManager"
14          class ="org.springframework.transaction.jta.JtaTransactionManager" >
15           < property  name ="transactionManager" >
16               < ref  bean ="atomikosTransactionManager"  />
17           property >
18           < property  name ="userTransaction" >
19               < ref  bean ="atomikosUserTransaction"  />
20           property >
21       bean >
22   < tx:annotation-driven  transaction-manager ="springTransactionManager"  proxy-target-class ="true"  />
2           < property  name ="basePackage"  value ="com.****.spring.dschange.mapper"  />
3           < property  name ="sqlSessionTemplateBeanName"  value ="sqlSessionTemplate" />
4           < property  name ="markerInterface"  value ="com.*****.spring.dschange.mapper.SqlMapper" />
5       bean >


最后就是JTA的实现配置

 1      
 2       < bean  id ="atomikosTransactionManager"  class ="com.atomikos.icatch.jta.UserTransactionManager"
 3          init-method ="init"  destroy-method ="close" >
 4           < property  name ="forceShutdown" >
 5               < value > true value >
 6           property >
 7       bean >
 8   
 9       < bean  id ="atomikosUserTransaction"  class ="com.atomikos.icatch.jta.UserTransactionImp" >
10           < property  name ="transactionTimeout"  value ="300"  />
11       bean >
12   
13       < bean  id ="springTransactionManager"
14          class ="org.springframework.transaction.jta.JtaTransactionManager" >
15           < property  name ="transactionManager" >
16               < ref  bean ="atomikosTransactionManager"  />
17           property >
18           < property  name ="userTransaction" >
19               < ref  bean ="atomikosUserTransaction"  />
20           property >
21       bean >
22   < tx:annotation-driven  transaction-manager ="springTransactionManager"  proxy-target-class ="true"  />

以上,XML配置相关的东西已经完成。
具体的代码,请点击GITHUB查看https://github.com/igool/spring-jta-mybatis

你可能感兴趣的:(spring,Atomikos,mybatis)