配置DataSource多数据源
使用场景:
同一个项目涉及多个数据库,既多数据源的情况。一般有两种情况:
1。两个数据库没有关系,各自独立,只是独立使用,并不相互使用。【我没有遇到这情况】
2。两个数据库,有相关性的,比如:主从master-slave。【我遇到的情况,oracle数据库,一个是主数据库,另一个是备份数据库只允许做查询】
【这两种解决的方法也是有对应的两种】【推荐使用,我是用这种的╮(╯_╰)╭】
在spring里面直接配置两个数据库的信息,两个数据库,两个事务,两个映射注入。【两套各自独立的东东】
所需要修改的配置:【spring-context.xml】
【以上的代码,是参考文章上copy的,没有试过】
大概的意思是酱紫的吧 :
事务【transactionManager】 → 数据源【DataSource】→映射SQL Factfactory 到对应XML →【sqlSessionFactory】 ← 配置sql注入 【MapperScannerConfigurer】;
事务【transactionManager2】 → 数据源【DataSource2】→映射SQL Factfactory 到对应XML →【sqlSessionFactory2】 ← 配置sql注入 【MapperScannerConfigurer2】;
这样依据配置的sql注入文件xml的目录,就对应到两个不同的数据源上了。
ps:这种方法配置很简单,就是配置两套完整的数据源,各种独立。
缺点是不够灵活,同一个sql要想在两个数据库执行则要在不同的配置目录下配置相同的文件,以及整个对应的东东bean,dao,service。
适合情况【我遇到的情况】:
项目使用oracle数据库,使用主从备份master-slave,master上允许所有的操作,为分摊master数据库压力,将耗时的查询放在slave上执行【项目master数据为多项目公用,数据库压力比较大】【项目数据库备份为单向备份,所以不允许在slave数据库上进行任何修改】
ps:由于备份数据库的实效性上有一定时间的延迟,对数据时效性要求高的查询必须在master上执行。
核心思想:
Spring在每次操作数据库的时候都会通过AbstractRoutingDataSource类中的determineTargetDataSource()方法获取当前数据源,我们就可以通过切面技术,在不同的切面,切入不同的数据源名称,使Spring获取的时候拿到的是不同的数据源。
而determineCurrentLookupKey()
方法是抽象的,所以,我们可以实现这个类,重写determineCurrentLookupKey方法,通过切面技术实现多数据源之间切换
具体实现如下:
SpringDataSource配置
Spring Configuration
ps:配置两个DataSource → 动态数据源【dynamicDataSource】;
ps:事务以及sqlSessionFactory → 动态数据源【dynamicDataSource】;
ps:动态数据源【dynamicDataSource】 配置 DynamicDataSource 动态数据源配置代码 对应spring 核心思想 中的获取操作数据源名称;【为空则使用默认数据源】
动态数据源:DynamicDataSource.java
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 多数据源切换
* @author xiaohang
* @date 2017/02/28
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal contextHolder = new ThreadLocal();
private static final String DATESOURCE_ONE = "dataSource";
private static final String DATESOURCE_TWO = "dataSource2";
/**
*
* @author sa
* @date 2012-5-18 下午4:06:44
* @return the currentLookupKey
*/
public static String getCurrentLookupKey() {
// System.out.println((String) contextHolder.get()); //测试使用
return (String) contextHolder.get();
}
/**
*
* @author xiaohang
* @date 2017/02/28
*/
public static void setdataSourceOne() {
contextHolder.set(DATESOURCE_ONE);
}
public static void setdataSourceTwo() {
contextHolder.set(DATESOURCE_TWO);
}
/*
* (non-Javadoc)
* 这个方法为spring核心执行数据库是会代用的方法
* @see
* org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#
* determineCurrentLookupKey()
*/
@Override
protected Object determineCurrentLookupKey() {
return getCurrentLookupKey();
}
}
使用示例:
try {
DynamicDataSource.setdataSourceTwo();
//数据操作
Page page = transDetailService.findPage(new Page(request, response), transDetail);
} catch (Exception e) {
e.printStackTrace();
}finally{
DynamicDataSource.setdataSourceOne();
}
ps:这个必须使用finally保证使用完数据库切换为默认,因为Spring的Controller为线程不安全的。如果不保证切换为默认数据源,则其他controller可能继续使用此线程,导致直接使用了数据源2进行操作【我的项目要求不允许这种情况发生】
疑问:
* 不知道可不可以在service层进行控制,多数据源的切换。【拜托各位路过的大神】
2017年3月4日 小杭
http://www.hifreud.com/2015/02/25/07-spring-datasources/ 【Spring 使用笔记之(四) - 配置DataSource多数据源】 ** 主要参考资料**
http://www.cnblogs.com/digdeep/p/4512368.html 【原理解析很具体】
http://ctrlc.iteye.com/blog/2248428