spring多數據源分布式事務的分析與解決方案


一、概述

  1、業務背景

  對老系統進行重構合並,導致新系統需要同時對3個數據庫進行管理。由於出現跨庫業務,需要實現分布式事務。

  2、開發環境

  spring框架版本  4.3.10.RELEASE

  持久層為結合mybatis寫的領域模型,如

  

  每一個entity對應數據庫的一張表,@DataSource注解(自定義)了對應數據源的key值。所以一個業務中可能存在數據源的切換。

  事務采用注解@Transaction驅動。

二、spring對多數據源的支持

  spring框架通過抽象類AbstractRoutingDataSource來實現多數據源支持。

  AbstractRoutingDataSource中有一個抽象方法determineCurrentLookupKey()。子類實現該方法即可。

  舉例如下:

package com.cmcc.cq.xx.common.mybatis;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {


    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSourceType();
    }

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setDataSourceType(String dataSourceType){
        contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType(){
        return contextHolder.get();
    }

    public static void clearDataSourceType(){
        contextHolder.remove();
    }
}

  ThreadLocal保存當前線程的數據源,執行數據庫操作之前會通過解析注解@DataSource設置下次操作的數據源類型,即相應的key值(見后文數據源配置)。

  

  到此,在不使用事務的情況下,可以完成多數據源切換。

三、spring分布式事務支持

  1、DataSourceTransactionManager不支持多數據源

  DataSourceTransactionManager事務管理器是一個單數據源事務管理器,在實例化時候會注入一個數據源。

<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dynamicDataSource">
	</property>
</bean>

  注意:雖然我們注入的是一個動態數據源,但是DataSourceTransactionManager不會因為我們使用動態數據源而跟着變化。

  因為DataSourceTransactionManager開始事務時獲取數據庫connection時並不是每次都通過dataSource來獲取,一般都是通過ConnectionHolder類獲得。

  

  所以開啟事務會報找不到表或視圖的異常。

  同時DataSourceTransactionManager也不能實現跨庫事務的一致性。

  2、JtaTransactionManager支持分布式事務

  JtaTransactionManager事務管理器只是提供一個接入方式,並沒有做相應的實現,目前比較流行的分布式事務第三方實現是atomikos和jotm。其中jotm更新日期是2010年,建議使用atomikos。

  兩者配置也是大同小異,以atomikos為例。

  引入maven依賴 

<dependency>  
    <groupId>com.atomikos</groupId>  
    <artifactId>transactions-jdbc</artifactId>  
    <version>3.7.0</version>  
</dependency>

  首先是數據源的配置,必須要使用類com.atomikos.jdbc.AtomikosDataSourceBean,不能再使用其他的連接池替代。xaDataSourceClassName要根據數據庫選擇相應的類,在數據庫對應的驅動包里可以找到。

<bean id="dataSource3" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">  
	    <property name="uniqueResourceName" value="key值"/>  
	    <property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>  
	    <property name="xaProperties">  
	        <props>  
	            <prop key="URL">${jdbc.dataSource.url3}</prop>  
	            <prop key="user">${jdbc.dataSource.username3}</prop>  
	            <prop key="password">${jdbc.dataSource.password3}</prop>  
	        </props>  
	    </property>  
	    <property name="minPoolSize" value="${jdbc.dataSource.minimumIdle3}" />  
	    <property name="maxPoolSize" value="${jdbc.dataSource.maximumPoolSize3}" />  
	    <property name="borrowConnectionTimeout" value="${jdbc.dataSource.connectionTimeout3}" />  
	    <property name="testQuery" value="${jdbc.dataSource.connectionTestQuery3}" />  
	    <property name="maintenanceInterval" value="60" />  
	    <property name="maxIdleTime" value="${jdbc.dataSource.idleTimeout3}"></property>
</bean>

  然后是JtaTransactionManager事務管理器配置。

  JtaTransactionManager有兩個重要屬性需要配置transactionManager和userTransaction。對應的配置類如下:

  

  注:在jotm中只需配置transactionManager屬性

  最后是atomikos的配置文件jta.properties。

  配置路徑:根路徑

  

  jta.properties也可命名為transactions.properties,如果不配置也可以啟動項目,因為幾乎所有配置項都有默認值。

  transactions.properties配置

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM