當數據量越來越多的時候,我們就會開始考慮跨庫查詢,讀寫分離,之前對於數據庫讀寫分離有過一定的瞭解,但是這裏面存在着一個問題,就是A庫中有a表,B庫中有b表,那如果b表出現了異常,a表這個時候怎麼回滾呢?當在一個數據庫中直接用事務很好的處理,那如果在多個數據源中呢?其實原理是一樣的。
對於一些較大的規模的應用,單個數據源已經無法支撐起龐大的用戶量,需要引入多數據源,水平層面進行分庫分表,降低DB的負載。另外,跨庫意味着單DB的事務就失效了,所以J2EE提出了JTA,分佈式事務管理,簡單的說,就是分2步提交,實際它有2個容器來管理,一個資源管理器,一個事務管理,在第一個階段中,所有參與全局事務的節點都開始準備,告訴事務管理器它們準備好提交了。第二階段,事務管理器告訴資源管理器執行commit或者rollback,如果任何一個節點顯示不能commit,那麼所有的節點全部rollback,下面我們來實現分佈式事務:
第一步:XA數據源定義
選定義一個抽象的父類源,這樣子類可以直接繼承
<!-- 兩個數據源的功用配置,方便下面直接引用 --> <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動態數據路由定義
<bean id="dataSource" class="com.icz.carcare.datasource.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <!-- write 數據更新和實時數據查詢--> <entry key="master" value-ref="masterSource"/> <!-- read 非實時數據查詢--> <entry key="slave" value-ref="slaveSource"/> </map> </property> <property name="defaultTargetDataSource" ref="masterSource"/> <!-- 默認使用master的數據源 --> </bean>
mybatis中進行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模板,注入相關配置 --> <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配置完了,現在就可以去實現跨庫事務的代碼編寫了。
下面我們來講講分佈式事務原理理解。
Innodb存儲引擎支持XA事務,通過XA事務可以支持分佈式事務的實現。分佈式事務指的是允許多個獨立的事務資源參與一個全局事務中。
全局事務要求其中所參與的事務要麼提交,要麼全部回滾。
XA事務允許不同數據庫之間的分佈式事務,如:一臺服務器是Mysql數據庫,一臺是Oracle的,又有可能還有一臺是sqlserver的,只要參與全部事務中每個節點都支持XA事務。分佈式事務可能在銀行系統的轉賬中比較常見,
#bank shanghai
update user_account set money=money+100 where user='xiaozhang';
#bank beijing
update user_account set money=money-100 where user='xiaoli';
像這種情況就是,要不都提交,要不都回滾。在任何一個節點出問題都會造成嚴重的問題,1 xiaozhang的賬號收到了錢,但是xiaoli沒有扣款 2.xiaozhang的賬號沒有收到錢,但是xiaoli扣款了
分佈式事務是由一個或者多個resource Managerd,一個事務管理器transaction manage以及一個應用程序application Program組成。
資源管理器:提供事務資源的方法,通常一個數據庫就是一個資源管理器
事務管理器:協調參與全部事務各個事務,需要和參與全局事務中的資源管理員進行通信。
應用程序:定義事務的邊界,指定全局事務中的操作。
在mysql分佈式事務中,資源管理器就是mysql數據庫,事務管理器爲連接到mysql服務器的客戶端。