最近做项目需要用到另一个数据库的内容,多方查找终于实现了功能。

我们都知道,在SSM框架中,我们在applicationContext.xml配置文件中添加数据源就可以实现数据库增删改查,但是只能连接一个数据库,这个时候我们就要从spring提供的源码下手看看有没有有关数据源切换的方法,找到关键源码(AbstractRoutingDataSource类,该类就相当于一个dataSource的调度者,用于根据key值来进行切换对应的dataSource。):

@Override

public Connection getConnection() throws SQLException {

return determineTargetDataSource().getConnection();

}

@Override

public Connection getConnection(String username, String password) throws SQLException {

return determineTargetDataSource().getConnection(username, password);

}

/**

* 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;

}

/**

* Determine the current lookup key. This will typically be

* implemented to check a thread-bound transaction context.

*

Allows for arbitrary keys. The returned key needs

* to match the stored lookup key type, as resolved by the

* {@link #resolveSpecifiedLookupKey} method.

*/

protected abstract Object determineCurrentLookupKey();

可以看出方法getConnection()调用的determineTargetDataSource则是关键方法,这个方法返回了具体使用的是哪个数据库;而

determineCurrentLookupKey()方法来返回当前数据源的key值。

将返回的key值在resolvedDataSources这个map中找到对应的value(当前使用的数据源)。 源码:

@Override

public void afterPropertiesSet() {

if (this.targetDataSources == null) {

throw new IllegalArgumentException("Property 'targetDataSources' is required");

}

this.resolvedDataSources = new HashMap(this.targetDataSources.size());

for (Map.Entry entry : this.targetDataSources.entrySet()) {

Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());

DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());

this.resolvedDataSources.put(lookupKey, dataSource);

}

if (this.defaultTargetDataSource != null) {

this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);

}

}

这个方法是通过targetDataSources对resolvedDataSources进行赋值的。targetDataSources我们可以用过配置文件进行配置,这样就可以设置当前使用哪个数据库了,但是需要先要准备一下前提条件。

1.我们先要重写上面的determineCurrentLookupKey方法,我们新建一个创建一个DynamicDataSource的类,用来获取自定义获取数据源的标识:

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

public class DynamicDataSource extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey() {

// 从自定义的位置获取数据源标识

return DynamicDataSourceHolder.getDataSource();

}

}

第二步:创建DynamicDataSourceHolder类用于切换要操作的数据源,代码如下:

package com.dingdao.apiserver.utils;

public class DynamicDataSourceHolder

{

private static final ThreadLocal THREAD_DATA_SOURCE = new ThreadLocal();

public static String getDataSource()

{

return (String)THREAD_DATA_SOURCE.get();

}

public static void setDataSource(String dataSource)

{

THREAD_DATA_SOURCE.set(dataSource);

}

public static void clearDataSource()

{

THREAD_DATA_SOURCE.remove();

}

}

第三步:创建DynamicDataSource.java类用于获取当前线程中使用的数据源,代码如下:

package com.dingdao.apiserver.utils;

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

public class DynamicDataSource

extends AbstractRoutingDataSource

{

protected Object determineCurrentLookupKey()

{

return DynamicDataSourceHolder.getDataSource();

}

}

到这里我们的前期的准备工作已经做完了,下面将我的配置文件粘贴出来:

jdbc.properties

driverClasss =com.mysql.jdbc.Driver(笔者用的mysql,如果不是mysql请自行替换)

jdbcUrl=jdbc:第一个数据库的链接

username=第一个数据库的用户名

password=第一个数据库的密码

jrt_driverClasss=com.mysql.jdbc.Driver(笔可以直接调用第一个的driverClasss,笔者只是用于看着舒服,啊哈哈)

jrt_jdbcUrl=jdbc:第二个数据库的链接

jrt_username=第二个数据库的用户名

jrt_password=第二个数据库的密码

#定义初始连接数

initialSize=0

#定义最大连接数

maxActive=20

#定义最大空闲

maxIdle=20

#定义最小空闲

minIdle=1

#定义最长等待时间

maxWait=60000

spring-mybatis.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.1.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx.xsd">

destroy-method="close">

destroy-method="close">

使用默认数据库的时候可以什么都不用写,但是切换为非默认数据库的时候就要进行设置了,下面把调用两种数据库的方法贴出来:

使用默认数据库的service的实现类代码:

@Autowired

@Qualifier("nitceDao")

NitceDao nitceDao;

public Map getNotice(Map map) {

List> notice = nitceDao.getNotice(map);

Map maps = new HashMap();

maps.put("lists", notice);

return maps;

}

不适用默认数据库service的实现类代码:

@Autowired

@Qualifier("testJRTDao")

private TestJRTDao testJRTDao;

public String AllColor() {

DynamicDataSourceHolder.setDataSource("jrt_dataSource");

JSONObject jsonObject = new JSONObject();

List> list = testJRTDao.selectAllColor();

jsonObject.put("AllColor",list);

return jsonObject.toString();

}

到这里两个数据库的切换已经可以实现了。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐