SSM项目实现连接两个mysql数据库
最近做项目需要用到另一个数据库的内容,多方查找终于实现了功能。
我们都知道,在SSM框架中,我们在applicationContext.xml配置文件中添加数据源就可以实现数据库增删改查,但是只能连接一个数据库,这个时候我们就要从spring提供的源码下手看看有没有有关数据源切换的方法,找到关键源码(AbstractRoutingDataSource类,该类就相当于一个dataSource的调度者,用于根据key值来进行切换对应的dataSource。
AbstractRoutingDataSource类:
@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我们可以用过配置文件进行配置,这样就可以设置当前使用哪个数据库了,但是需要先要准备一下前提条件。
第一步:我们先要重写上面的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();
}
}
到这里我们的前期的准备工作已经做完了,下面将我的配置文件粘贴出来:
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();
}
到这里两个数据库的切换已经可以实现了。
SSM项目实现连接两个mysql数据库的更多相关文章
- Windows安装两个mysql数据库步骤
因为新旧项目数据库版本号差距太大.编码格式不同.引擎也不同,所以仅仅好装两个数据库. 本次安装两个mysql数据库.版本号各自是4.0.18,5.5.36.都是可运行文件直接安装. 本机上之前已经安装 ...
- 两台Mysql数据库数据同步实现
两台Mysql数据库数据同步实现 做开发的时候要做Mysql的数据库同步,两台安装一样的系统,都是FreeBSD5.4,安装了Apache 2.0.55和PHP 4.4.0,Mysql的版本是4.1. ...
- R语言使用RMySQL连接及读写Mysql数据库 测试通过
R语言使用RMySQL连接及读写Mysql数据库 简单说下安装过程,一般不会有问题,重点是RMySQL的使用方式. 系统环境说明 Redhat系统:Linux 460-42.6.32-431.29.2 ...
- linux下程序JDBC连接不到mysql数据库
今天在linux下部署一个 JavaEE项目的时候总是连接不到Mysql数据库,检查之后发现连接池的配置确定是对的,进入linux服务器之后以mysql -uname -ppassword连接总是报A ...
- JAVA连接SqlServer2008R2和MySql数据库
问题描述: 下面是有关连接SqlServer2008R2和MySql数据库的封装类 package com.test; import java.sql.Connection; import java. ...
- 寝室远程连接室友mysql数据库
注意,本方法是适用于同一局域网下的远程连接 注意,本方法是适用于同一局域网下的远程连接 注意,本方法是适用于同一局域网下的远程连接 首先需要修改mysql数据库的相关配置,将user表中的host改为 ...
- robot_framewok自动化测试--(9)连接并操作 MySql 数据库
连接并操作 MySql 数据库 1.mysql数据库 1.1安装mysql数据库 请参考我的另一篇文章:MYSQL5.7下载安装图文教程 1.2.准备测试数据 请参考我的另一篇文章:Mysql基础教程 ...
- Spring Boot项目中MyBatis连接DB2和MySQL数据库返回结果中一些字符消失——debug笔记
写这篇记录的原因是因为我之前在Spring Boot项目中通过MyBatis连接DB2返回的结果中存在一些字段, 这些字段的元素中缺少了一些符号,所以我现在通过在自己的电脑上通过MyBatis连接DB ...
- SQL多表连接查询以及mysql数据库、sqlserver数据库常见不同点
mysql数据库表及数据准备语句: USE test; DROP TABLE IF EXISTS `teacher_table`; DROP TABLE IF EXISTS `student_tabl ...
随机推荐
- tensorflow 模型加载(没有checkpoint文件或者说只加载其中一个模型)
1.如果有checkpoint文件的话,加载模型很简单: 第一步:都是加载图: with tf.Session() as sess: saver=tf.train.import_meta_graph( ...
- CSS如何让文字垂直居中?
在说到这个问题的时候,也许有人会问CSS中不是有vertical-align属性来设置垂直居中的吗?即使是某些浏览器不支持我只需做少许的CSS Hack技术就可以啊!所以在这里我还要啰嗦两句,CSS中 ...
- palindrome 回文 /// Manacher算法
判断最长不连续回文 #include <bits/stdc++.h> using namespace std; int main() { ]; while(gets(ch)) { ],an ...
- 回车切换input选框
在工作中许多时候需要考虑到用户体验,当按下回车键时切换input选框就来得十分必要. <!DOCTYPE HTML> <html> <head> <meta ...
- VSCode 常用setiings.json设置
{ , , "editor.multiCursorModifier": "ctrlCmd", "editor.snippetSuggestions&q ...
- PHP算法之字符串转换整数 (atoi)
请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之 ...
- python 封装一个取符串长度的函数
def getStrLen(str): return len(str) print(getStrLen("dsa456das4dasdas21"))
- css实现单行、多行文本溢出显示省略号(…)
一.单行文本溢出显示省略号(…) 省略号在ie中可以使用text-overflow:ellipsis了,但有很多的浏览器都需要固定宽度了,同时ff这些浏览器并不支持text-overflow:elli ...
- leetcode-90-子集②
题目描述: 方法一:回溯 class Solution: def subsetsWithDup(self, nums: List[int]) -> List[List[int]]: nums.s ...
- [JZOJ6258] 【省选模拟8.9】轰炸
题目 题目大意 给你一棵树和树上的许多条从后代到祖先的链,选择每条链需要一定代价,问覆盖整棵树的所有点的最小代价是多少. \(n,m\leq 100000\) 正解 (由于时间过于久远,所以直接说正解 ...