隨筆-35  評論-33  文章-0  trackbacks-0
               本文的幾個關鍵詞,分布式數據源,數據源的動態尋找,分布式事務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     <!-- value只要兩個數據源不同就行,隨便取名 -->
           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 <!-- value只要兩個數據源不同就行,隨便取名 -->
           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          <!-- mapper和resultmap配置路徑 --> 
           5         <property name="mapperLocations">
           6             <list>
           7                 <!-- 表示在com.**目錄下的任意包下的resultmap包目錄中,以-resultmap.xml或-mapper.xml結尾所有文件 --> 
           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           <!-- mapper和resultmap配置路徑 --> 
          16         <property name="mapperLocations">
          17             <list>
          18                 <!-- 表示在com.***目錄下的任意包下的resultmap包目錄中,以-resultmap.xml或-mapper.xml結尾所有文件 --> 
          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  <!-- 配置自定義的SqlSessionTemplate模板,注入相關配置 -->
           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     <!-- jta -->
           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     <!-- jta -->
           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


          我的微信公眾號,歡迎溝通學習。
          posted on 2015-09-24 14:29 alexcai 閱讀(7106) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 龙游县| 昌江| 新乡市| 漳浦县| 涟水县| 龙海市| 普兰县| 驻马店市| 法库县| 犍为县| 奎屯市| 牡丹江市| 新乡县| 陇西县| 新巴尔虎左旗| 伽师县| 洪洞县| 怀安县| 金门县| 武清区| 通河县| 舒兰市| 清原| 两当县| 共和县| 津市市| 新乡市| 土默特右旗| 岳普湖县| 习水县| 黄梅县| 绥滨县| 梁平县| 河间市| 织金县| 密云县| 唐河县| 广水市| 当雄县| 白银市| 阳谷县|