SpringMVC 利用AbstractRoutingDataSource实现动态数据源切换

本文转载至:http://exceptioneye.iteye.com/blog/1698064

Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。

Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况: 
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。 
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。 
Spring2.x的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。 
具体的实现就是,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。

一、原理

首先看下AbstractRoutingDataSource类结构,继承了AbstractDataSource

<span>public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean</span>

既然是AbstractDataSource,当然就是javax.sql.DataSource的子类,于是我们自然地回去看它的getConnection方法:

<span>public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
} public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}</span>

原来关键就在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;
}

这里用到了我们需要进行实现的抽象方法determineCurrentLookupKey(),该方法返回需要使用的DataSource的key值,然后根据这个key从resolvedDataSources这个map里取出对应的DataSource,如果找不到,则用默认的resolvedDefaultDataSource。

    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 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);
}
}

二、Spring配置多数据源的方式和具体使用过程

建立一个获得和设置上下文环境的类,主要负责改变上下文数据源的名称

public class DynamicDataSourceHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
} public static String getDataSourceType() {
return contextHolder.get();
} public static void clearDataSourceType() {
contextHolder.remove();
} }

建立动态数据源类,注意,这个类必须继承AbstractRoutingDataSource,且实现方法 determineCurrentLookupKey,该方法返回一个Object,一般是返回字符串

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSourceType();
} }

编写spring的配置文件配置多个数据源

<!-- 数据源相同的内容 -->

    <bean id="parentDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClass"
value="oracle.jdbc.pool.OracleConnectionPoolDataSource" />
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" />
<property name="user" value="isc_v10" />
<property name="password" value="isc" />
</bean> <!-- 数据源 -->
<bean id="orclDataSource" parent="parentDataSource">
<property name="user" value="orcl" />
<property name="password" value="orcl" />
</bean> <!-- 数据源 -->
<bean id="iscDataSource" parent="parentDataSource">
<property name="user" value="isc_v10" />
<property name="password" value="isc" />
</bean> <!-- 编写spring 配置文件的配置多数源映射关系 -->
<bean id="dataSource" class="com.wy.config.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="ORCL" value-ref="orclDataSource"></entry>
<entry key="ISC" value-ref="iscDataSource"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="orclDataSource">
</property>
</bean> <bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>

测试

    public void testSave() {
// hibernate创建实体
DynamicDataSourceHolder.setDataSourceType(DynamicDataSourceGlobal.ORCL);// 设置为另一个数据源
com.wy.domain.Test user = new com.wy.domain.Test(); user.setName("WY");
user.setAddress("BJ"); testDao.save(user);// 使用dao保存实体 DynamicDataSourceHolder.setDataSourceType(DynamicDataSourceGlobal.ISC);// 设置为另一个数据源 testDao.save(user);// 使用dao保存实体到另一个库中 }

SpringMVC 利用AbstractRoutingDataSource实现动态数据源切换的更多相关文章

  1. 利用AbstractRoutingDataSource实现动态数据源切换

    需求:系统中要实现切换数据库(业务数据库和his数据库) 网上很多资料上有提到AbstractRoutingDataSource,大致是这么说的 在Spring 2.0.1中引入了AbstractRo ...

  2. AbstractRoutingDataSource 实现动态数据源切换原理简单分析

    AbstractRoutingDataSource 实现动态数据源切换原理简单分析 写在前面,项目中用到了动态数据源切换,记录一下其运行机制. 代码展示 下面列出一些关键代码,后续分析会用到 数据配置 ...

  3. Spring(AbstractRoutingDataSource)实现动态数据源切换--转载

    原始出处:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目 ...

  4. AbstractRoutingDataSource实现动态数据源切换 专题

    需求:系统中要实现切换数据库(业务数据库和his数据库) 网上很多资料上有提到AbstractRoutingDataSource,大致是这么说的 在Spring 2.0.1中引入了AbstractRo ...

  5. Spring(AbstractRoutingDataSource)实现动态数据源切换

    转自: http://blog.51cto.com/linhongyu/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中切换数据源,直 ...

  6. spring AbstractRoutingDataSource实现动态数据源切换

    使用Spring 提供的 AbstractRoutingDataSource 实现 创建 AbstractRoutingDataSource 实现类,负责保存所有数据源与切换数据源策略:public ...

  7. Spring 实现动态数据源切换--转载 (AbstractRoutingDataSource)的使用

    [参考]Spring(AbstractRoutingDataSource)实现动态数据源切换--转载 [参考] 利用Spring的AbstractRoutingDataSource解决多数据源的问题 ...

  8. 【开发笔记】- AbstractRoutingDataSource动态数据源切换,AOP实现动态数据源切换

    AbstractRoutingDataSource动态数据源切换 上周末,室友通宵达旦的敲代码处理他的多数据源的问题,搞的非常的紧张,也和我聊了聊天,大概的了解了他的业务的需求.一般的情况下我们都是使 ...

  9. AbstractRoutingDataSource动态数据源切换,AOP实现动态数据源切换

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u012881904/article/de ...

随机推荐

  1. java多线程(一)之继承Thread类

    一.概述 进程:正在执行的应用程序 线程:进程的执行单元,执行路径 单线程:一个应用程序只有一条执行路径 多线程:一个应用程序有多条执行路径 二.两种实现方式, 下面为第一种方式: 继承Thread类 ...

  2. 转inux Shell编程入门

    http://www.cnblogs.com/suyang/archive/2008/05/18/1201990.html 从程序员的角度来看, Shell本身是一种用C语言编写的程序,从用户的角度来 ...

  3. JMeter分布式配置

    搭建进行分布式平台测试前提: 1 所有的防火墙应该关闭 2 所有的客户端应该都是在同一个子网中. 3 确保jMeter可以访问这个服务器 4 确保各个客户端的jMeter的版本都是一致的,不同版本的J ...

  4. RHEL7 -- NetworkManager

    RHEL7中默认的网络服务是由NetworkManager提供,NetworkManager可以动态控制和配置网络. 网络工具和应用 应用或工具 描述 NetworkManager 默认的网络守护进程 ...

  5. IIS下浏览指定文件(如:web.config)

    具体步骤如下: 1.快捷键:Ctrl + R 2.输入:%windir%\System32\inetsrv\config\applicationHost.config 3.注销:fileExtensi ...

  6. Note for video Machine Learning and Data Mining——training vs Testing

    Here is the note for lecture five. There will be several points  1. Training and Testing  Both of th ...

  7. 常用IP核

    前言 记录自己用到的模块,随时补充. 主要分类: 一.常用模块 1-FIFO FIFO分为两种,一是输入输出时钟相同(Common clock)的 fifo ;二是输入输出时钟不相同(Independ ...

  8. spine 2.1.27 Pro 叠加方式(Blending)

    将spine更新到2.1.27 Pro,发现有更多的叠加方式可用了,如图: 以前则只有Normal和Additive可选. 更多的叠加方式对于用spine做特效动画还是比较有用的.不过我还没试这些叠加 ...

  9. Oracle中查询表字段基本信息、主键、外键(整理)

    背景 因为项目某些模块的数据结构设计没有严格按照某规范设计,所以只能从数据库中查询数据结构,需要查询的信息如下:字段名称.数据类型.是否为空.默认值.主键.外键等等. 在网上搜索了查询上述信息的方法, ...

  10. shu_1232 老王赛马

    http://202.121.199.212/JudgeOnline/problem.php?cid=1078&pid=2 分析:贪心. 用我方最好的马去解决可以解决的对方的最好的马,如是才干 ...