大型應(yīng)用中,會有如下的情況,Peter老師希望大家能考慮到,這個比較符合實際情況。
當(dāng)數(shù)據(jù)量越來越多的時候,我們就會開始考慮跨庫查詢,讀寫分離,之前對于數(shù)據(jù)庫讀寫分離有過一定的了解,但是這里面存在著一個問題,就是A庫中有a表,B庫中有b表,那如果b表出現(xiàn)了異常,a表這個時候怎么回滾呢?當(dāng)在一個數(shù)據(jù)庫中直接用事務(wù)很好的處理,那如果在多個數(shù)據(jù)源中呢?其實原理是一樣的。
對于一些較大的規(guī)模的應(yīng)用,單個數(shù)據(jù)源已經(jīng)無法支撐起龐大的用戶量,需要引入多數(shù)據(jù)源,水平層面進(jìn)行分庫分表,降低DB的負(fù)載。另外,跨庫意味著單DB的事務(wù)就失效了,所以J2EE提出了JTA,分布式事務(wù)管理,簡單的說,就是分2步提交,實際它有2個容器來管理,一個資源管理器,一個事務(wù)管理,在第一個階段中,所有參與全局事務(wù)的節(jié)點都開始準(zhǔn)備,告訴事務(wù)管理器它們準(zhǔn)備好提交了。第二階段,事務(wù)管理器告訴資源管理器執(zhí)行commit或者rollback,如果任何一個節(jié)點顯示不能commit,那么所有的節(jié)點全部rollback,下面我們來實現(xiàn)分布式事務(wù):
XA協(xié)議是分布事務(wù)處理中子事務(wù)與全局事務(wù)間通訊的接口規(guī)范。
第一步:XA數(shù)據(jù)源定義
???? 選定義一個抽象的父類源,這樣子類可以直接繼承
<!-- 兩個數(shù)據(jù)源的功用配置,方便下面直接引用 -->
<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"? ? ? destroy-method="close">
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="poolSize" value="10" />
<property name="minPoolSize" value="10"/>
<property name="maxPoolSize" value="30"/>
<property name="borrowConnectionTimeout" value="60"/>
<property name="reapTimeout" value="20"/>
<!-- 最大空閑時間 -->? ??
<property name="maxIdleTime" value="60"/>
<property name="maintenanceInterval" value="60" />
<property name="loginTimeout" value="60"/>
<property name="logWriter" value="60"/>
<property name="testQuery">
<value>select 1</value>
</property>
</bean>
?master源
<bean id="masterSource" parent="abstractXADataSource">? ? <property name="uniqueResourceName">? ? ? ? <value>master</value>? ? </property>? ? <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />? ? <property name="xaProperties">? ? ? ? <props>? ? ? ? ? ? <prop key="user">庫用戶名</prop>? ? ? ? ? ? <prop key="password">庫密碼</prop>? ? ? ? ? ? <prop key="URL">master庫連接</prop>? ? ? ? </props>? ? </property></bean>
slave源
<bean id="slaveSource" parent="abstractXADataSource">? ? <property name="uniqueResourceName">? ? ? ? <value>slave</value>? ? </property>? ? <property name="xaDataSourceClassName">? ? ? ? <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>? ? </property>? ? <property name="xaProperties">? ? ? ? <props>? ? ? ? ? ? <prop key="user">庫用戶名</prop>? ? ? ? ? ? <prop key="password">庫密碼</prop>? ? ? ? ? ? <prop key="URL">slave庫連接</prop>? ? ? ? </props>? ? </property></bean>
基于spring的AbstractRoutingDataSource動態(tài)數(shù)據(jù)路由定義
<bean id="dataSource" class="com.icz.carcare.datasource.DynamicDataSource"><property name="targetDataSources"><map key-type="java.lang.String"><!-- write 數(shù)據(jù)更新和實時數(shù)據(jù)查詢-->? ? ? ? ? ? <entry key="master" value-ref="masterSource"/><!-- read 非實時數(shù)據(jù)查詢-->? ? ? ? ? ? <entry key="slave" value-ref="slaveSource"/></map></property><property name="defaultTargetDataSource" ref="masterSource"/><!-- 默認(rèn)使用master的數(shù)據(jù)源 --></bean>
mybatis中進(jìn)行ORM映射
<bean id="sqlSessionFactorya" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="masterSource"/><!-- 自動掃描sqlmaps目錄, 省掉Configuration.xml里的手工配置 -->? ? <property name="mapperLocations" value="classpath*:Msqlmaps/*.xml" /></bean><bean id="sqlSessionFactoryb" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="slaveSource" /><!-- 自動掃描sqlmaps目錄, 省掉Configuration.xml里的手工配置 -->? ? <property name="mapperLocations" value="classpath*:Msqlmaps/*.xml" /></bean>
配置sessionTemplate模板
<!-- 配置自定義的SqlSessionTemplate模板,注入相關(guān)配置 --><bean id="sqlSessionTemplate" class="com.icz.carcare.sqlSessionTemplate.CustomSqlSessionTemplate"><constructor-arg ref="sqlSessionFactorya" /><property name="targetSqlSessionFactorys"><map><entry value-ref="sqlSessionFactorya" key="master"/><entry value-ref="sqlSessionFactoryb" key="slave"/></map></property></bean>
jta配置
<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>
以上xml配置完了,現(xiàn)在就可以去實現(xiàn)跨庫事務(wù)的代碼編寫了。
下面我們來講講分布式事務(wù)原理理解。
Innodb存儲引擎支持XA事務(wù),通過XA事務(wù)可以支持分布式事務(wù)的實現(xiàn)。分布式事務(wù)指的是允許多個獨立的事務(wù)資源參與一個全局事務(wù)中。
全局事務(wù)要求其中所參與的事務(wù)要么提交,要么全部回滾。
XA事務(wù)允許不同數(shù)據(jù)庫之間的分布式事務(wù),如:一臺服務(wù)器是Mysql數(shù)據(jù)庫,一臺是Oracle的,又有可能還有一臺是sqlserver的,只要參與全部事務(wù)中每個節(jié)點都支持XA事務(wù)。分布式事務(wù)可能在銀行系統(tǒng)的轉(zhuǎn)賬中比較常見,
#bank shanghai
update user_account set money=money+100 where user='xiaozhang';
#bank beijing
update user_account set money=money-100 where user='xiaoli';
像這種情況就是,要不都提交,要不都回滾。在任何一個節(jié)點出問題都會造成嚴(yán)重的問題,1 xiaozhang的賬號收到了錢,但是xiaoli沒有扣款 2.xiaozhang的賬號沒有收到錢,但是xiaoli扣款了
分布式事務(wù)是由一個或者多個resource Managerd,一個事務(wù)管理器transaction manage以及一個應(yīng)用程序application Program組成。
資源管理器:提供事務(wù)資源的方法,通常一個數(shù)據(jù)庫就是一個資源管理器
事務(wù)管理器:協(xié)調(diào)參與全部事務(wù)各個事務(wù),需要和參與全局事務(wù)中的資源管理員進(jìn)行通信。
應(yīng)用程序:定義事務(wù)的邊界,指定全局事務(wù)中的操作。
在mysql分布式事務(wù)中,資源管理器就是mysql數(shù)據(jù)庫,事務(wù)管理器為連接到mysql服務(wù)器的客戶端