spring 中多數據源的配置

黎明的到來,黑暗將消失殆盡。

我喜歡冷的天氣,因爲他可以讓我毫無顧忌的多睡一會。今天早上再微信公衆好看到這樣一句話,挺勵志的,就拿出來跟大家share下。

I am a slow walker,but I never walk backwards.(我希望大家不是用他來安慰自己的,而是讓自己更有動力向前行)

今天跟大家分享的知識是spring中的動態多數據源的修改,直接點就是用戶可以任意的切換數據庫。

一.首先建立一個可以修改數據源名字的一個類:DatasourceContextHolder

給大家貼代碼:

public class DatasourceContextHolder {

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

	public static void setDatatsource(String datasoruce) {
		contextHolder.set(datasoruce);
	}

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

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

大家可能對
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();<pre name="code" class="java">/** 
     * Retrieve the current target DataSource. Determines the 
     * {@link #determineCurrentLookupKey() current lookup key}, performs 
     * a lookup in the {@link #setTargetDataSources targetDataSources} map, 
     * falls back to the specified 
     * {@link #setDefaultTargetDataSource default target DataSource} if necessary. 
     * @see #determineCurrentLookupKey() 
     */  
    protected DataSource determineTargetDataSource() {  
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");  
        Object lookupKey = determineCurrentLookupKey();  
        DataSource dataSource = this.resolvedDataSources.get(lookupKey);  
        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {  
            dataSource = this.resolvedDefaultDataSource;  
        }  
        if (dataSource == null) {  
            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");  
        }  
        return dataSource;  
    }


不是很明白他的具體作用,我在這裏說明下:我們再這個類裏聲明瞭一個本地的線程對象,他主要是可以保存當前調用該類的一個string,他是一個局部的變量,這樣我們在不同的用戶切換數據源的時候就不會有衝突。

上面我們已經實現了database的一個上下文的環境,現在我們要考慮的問題就是如何根據我們修改的值把他set到db的connection呢?下面我們就介紹這部分內容。

二.內部修改DBSource的一個實現

首先上代碼,然後解釋:

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

public class CustomerRoutingDataSource extends AbstractRoutingDataSource{

	
	@Override
	protected Object determineCurrentLookupKey() {
		// TODO Auto-generated method stub
		return DatasourceContextHolder.getDatasource();
	}

}

上面是建立動態數據源類,我們必須要繼承AbstractRoutingDataSource,並且要實現determineCurrentLookupKey方法。這是爲什麼呢,我們一步一步來,我先從概念上說明下: 在Spring 2.0.1中引入了AbstractRoutingDataSource, 該類充當了DataSource的路由中介, 能有在運行時, 根據某種key值來動態切換到真正的DataSource上。

而在我們繼承的AbstractRoutingDataSource類中,他同樣繼承了AbstractDataSource(java.sql.datasource裏面的一個類),我們發現在他的getconnection方法中返回了一個值determineTargetDataSource(),然後我們繼續深入發現了好東西,我展示代碼給大家看:

/** 
     * Retrieve the current target DataSource. Determines the 
     * {@link #determineCurrentLookupKey() current lookup key}, performs 
     * a lookup in the {@link #setTargetDataSources targetDataSources} map, 
     * falls back to the specified 
     * {@link #setDefaultTargetDataSource default target DataSource} if necessary. 
     * @see #determineCurrentLookupKey() 
     */  
    protected DataSource determineTargetDataSource() {  
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");  
        Object lookupKey = determineCurrentLookupKey();  
        DataSource dataSource = this.resolvedDataSources.get(lookupKey);  
        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {  
            dataSource = this.resolvedDefaultDataSource;  
        }  
        if (dataSource == null) {  
            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");  
        }  
        return dataSource;  
    }

在這裏determineTargetDataSource()中,我們的determineCurrentLookupKey()會返回一個dataSource的一個名字,然後
DataSource dataSource = this.resolvedDataSources.get(lookupKey); 

這句話會根據所給的lookupkey從resolvedDataSources中map中找對應的key,如果有就會配置相應的數據源,沒有的沒有就使用默認的數據源,下面我先把map中的部分內容展示給大家看:(ep:lookupKey="b2bappstg",map--->key="b2bappstg")

<beans:bean id="dataSource" class="com.xxx.xxx.xxx.xxx.CustomerRoutingDataSource">
		<beans:property name="targetDataSources">
			<beans:map>
				<beans:entry key="test1" value-ref="Test1" />
				<beans:entry key="test2" value-ref="Test2" />
				<beans:entry key="test3" value-ref="Test3" />
			</beans:map>
		</beans:property>
		<beans:property name="defaultTargetDataSource" ref="Test1" />
	</beans:bean>
接下來的工作我們就比較簡單了,就是在spring配置文件中配置你的多數據源。

三.編寫spring中的多數據源

這裏給大家放一個模板就可以了,然後你只需修改你自己的datasource就可以了:

<beans:bean id="Test1" class="org.springframework.jdbc.datasource.DriverManagerDataSource" abstract="true">
		<beans:property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<beans:property name="username" value="xxxxxx" />
		<beans:property name="password" value="xxxxxx" />
	</beans:bean>
	<beans:bean id="Test2" class="org.springframework.jdbc.datasource.DriverManagerDataSource" parent="Test2">
		<beans:property name="url" value="oracle.jdbc.driver.OracleDriver" />
	</beans:bean>	
	<beans:bean id="Test3" class="org.springframework.jdbc.datasource.DriverManagerDataSource" parent="Test3">
		<beans:property name="url" value="oracle.jdbc.driver.OracleDriver" />
	</beans:bean>
<pre name="code" class="html">       <beans:bean id="dataSource" class="com.xxx.xxx.xxx.xxx.CustomerRoutingDataSource">
		<beans:property name="targetDataSources">
			<beans:map>
				<beans:entry key="test1" value-ref="Test1" />
				<beans:entry key="test2" value-ref="Test2" />
				<beans:entry key="test3" value-ref="Test3" />
			</beans:map>
		</beans:property>
		<beans:property name="defaultTargetDataSource" ref="Test1" />
	</beans:bean>
       <beans:bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
           <beans:property name="dataSource" ref="dataSource" />
           <beans:property name="mapperLocations" value="classpath*:com/XXXX/XXX/XXX/XXX/*.xml" />
        </beans:bean>

以上就全部的配置過程,下面你就可以在你的controller或者action中應用下面這句話就可以完成數據源的動態性。

DatasourceContextHolder.setDatatsource("test1 or test2 or test3");

最後讓大家輕鬆下:


   一隻小狗爬上你的餐桌,向一隻燒雞爬去,你大怒道:你敢對那隻燒雞怎樣,我就敢對你怎樣,結果小狗舔了一下雞屁股,你昏倒,小狗樂道:小樣看誰狠。

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