本文的幾個關鍵詞,分布式數據源,數據源的動態尋找,分布式事務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 閱讀(7104)
評論(0) 編輯 收藏