spring 中多数据源的配置

来源:互联网 发布:印尼网络怎么样 编辑:程序博客网 时间:2024/05/20 14:43

黎明的到来,黑暗将消失殆尽。

我喜欢冷的天气,因为他可以让我毫无顾忌的多睡一会。今天早上再微信公众好看到这样一句话,挺励志的,就拿出来跟大家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{@Overrideprotected Object determineCurrentLookupKey() {// TODO Auto-generated method stubreturn 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");

最后让大家轻松下:


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

0 0