spring分佈式事務實現

當數據量越來越多的時候,我們就會開始考慮跨庫查詢,讀寫分離,之前對於數據庫讀寫分離有過一定的瞭解,但是這裏面存在着一個問題,就是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服務器的客戶端。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章