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");

最后让大家轻松下:


   一只小狗爬上你的餐桌,向一只烧鸡爬去,你大怒道:你敢对那只烧鸡怎样,我就敢对你怎样,结果小狗舔了一下鸡屁股,你昏倒,小狗乐道:小样看谁狠。

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