最近做项目需要用到另一个数据库的内容,多方查找终于实现了功能。
我们都知道,在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. * <p>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<Object,
DataSource>(this.targetDataSources.size()); for (Map.Entry<Object, Object>
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<String> 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
<?xml version="1.0" encoding="UTF-8"?> <beans
xmlns="http://www.springframework.org/schema/beans"
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"> <!-- 自动扫描 -->
<context:component-scan base-package="com.dingdao.apiserver.*"/> <!--
第一种方式:加载一个properties文件 --> <bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/> </bean> <!--
配置第一个数据源 --> <bean id="defultdataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${driverClasss}"/> <property name="url"
value="${jdbcUrl}"/> <property name="username" value="${username}"/> <property
name="password" value="${password}"/> <!-- 初始化连接大小 --> <property
name="initialSize" value="${initialSize}"></property> <!-- 连接池最大数量 -->
<property name="maxActive" value="${maxActive}"></property> <!-- 连接池最大空闲 -->
<property name="maxIdle" value="${maxIdle}"></property> <!-- 连接池最小空闲 -->
<property name="minIdle" value="${minIdle}"></property> <!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${maxWait}"></property> </bean> <!-- 配置第二个数据源
--> <bean id="jrt_dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"> <property name="driverClassName"
value="${jrt_driverClasss}"/> <property name="url" value="${jrt_jdbcUrl}"/>
<property name="username" value="${jrt_username}"/> <property name="password"
value="${jrt_password}"/> <!-- 初始化连接大小 --> <property name="initialSize"
value="${initialSize}"></property> <!-- 连接池最大数量 --> <property name="maxActive"
value="${maxActive}"></property> <!-- 连接池最大空闲 --> <property name="maxIdle"
value="${maxIdle}"></property> <!-- 连接池最小空闲 --> <property name="minIdle"
value="${minIdle}"></property> <!-- 获取连接最大等待时间 --> <property name="maxWait"
value="${maxWait}"></property> </bean> <bean id="dataSource"
class="com.dingdao.apiserver.utils.DynamicDataSource"> <property
name="targetDataSources"> <map key-type="java.lang.String"> <!--
指定lookupKey和与之对应的数据源,这里的key可以自行定义,要切换数据库的时候以key为标识,不要写错 --> <entry
key="defultdataSource" value-ref="defultdataSource"></entry> <entry
key="jrt_dataSource" value-ref="jrt_dataSource"></entry> </map> </property>
<!-- 这里可以指定默认的数据源 --> <property name="defaultTargetDataSource"
ref="defultdataSource" /> </bean> <!-- mybatis和spring完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/> <!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean> <!-- DAO接口所在包名,Spring会自动查找其下的类 --> <bean
class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property
name="basePackage" value="com.dingdao.apiserver.dao"/> <property
name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean>
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/> </bean> <!-- (事务管理)transaction
manager, use JtaTransactionManager for global tx --> <tx:annotation-driven
transaction-manager="transactionManager"/> </beans>
使用默认数据库的时候可以什么都不用写,但是切换为非默认数据库的时候就要进行设置了,下面把调用两种数据库的方法贴出来:
使用默认数据库的service的实现类代码:
@Autowired @Qualifier("nitceDao") NitceDao nitceDao; public Map<String,
Object> getNotice(Map<String, Object> map) { List<Map<String, Object>> notice =
nitceDao.getNotice(map); Map<String,Object> maps = new HashMap<String,
Object>(); 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<Map<String ,Object>> list =
testJRTDao.selectAllColor(); jsonObject.put("AllColor",list); return
jsonObject.toString(); }
到这里两个数据库的切换已经可以实现了。
热门工具 换一换