Spring实现动态切换多数据源的解决方案

所属分类: 软件编程 / java 阅读数: 35
收藏 0 赞 0 分享

前言

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

Spring2.x以后的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。

实现

具体的实现就是,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。

一、动态配置多数据源

1. 数据源的名称常量类:

/** 
 * 动态配置多数据源 
 * 数据源的名称常量类 
 * @author LONGHUI_LUO 
 * 
 */ 
public class DataSourceConst { 
 public static final String TEST="test"; 
 public static final String USER="User"; 
} 

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

/** 
 * 获得和设置上下文环境 主要负责改变上下文数据源的名称 
 * 
 * @author LONGHUI_LUO 
 * 
 */ 
public class DataSourceContextHolder { 
 private static final ThreadLocal contextHolder = new ThreadLocal(); // 线程本地环境 
 
 // 设置数据源类型 
 public static void setDataSourceType(String dataSourceType) { 
  contextHolder.set(dataSourceType); 
 } 
 
 // 获取数据源类型 
 public static String getDataSourceType() { 
  return (String) contextHolder.get(); 
 } 
 
 // 清除数据源类型 
 public static void clearDataSourceType() { 
  contextHolder.remove(); 
 } 
 
} 

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

/** 
 * 建立动态数据源 
 * 
 * @author LONGHUI_LUO 
 * 
 */ 
public class DynamicDataSource extends AbstractRoutingDataSource { 
 
 protected Object determineCurrentLookupKey() { 
 // 在进行DAO操作前,通过上下文环境变量,获得数据源的类型 
 return DataSourceContextHolder.getDataSourceType(); 
 } 
 
} 

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

  <!-- 数据源相同的内容 --> 
<bean 
  id="parentDataSource" 
  class="org.apache.commons.dbcp.BasicDataSource" 
  destroy-method="close"> 
  <property 
   name="driverClassName" 
   value="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> 
  <property name="username" value="sa" /> 
  <property name="password" value="net2com" /> 
</bean> 
<!-- start以下配置各个数据源的特性 --> 
<bean parent="parentDataSource" id="testDataSource"> 
  <propertynamepropertyname="url" value="jdbc:sqlserver://localhost:1433;databaseName=test" /> 
</bean> 
<bean parent="parentDataSource" id="UserDataSource"> 
   <property 
   name="url" 
   value="jdbc:sqlserver://localhost:1433;databaseName=User" /> 
</bean> 
<!-- end 配置各个数据源的特性 --> 

5. 编写spring配置文件配置多数据源映射关系

<bean class="com.xxxx.datasouce.DynamicDataSource" id="dataSource"> 
 <property name="targetDataSources"> 
  <map key-type="java.lang.String"> 
   <entry value-ref="testDataSource" key="test"></entry> 
   <entry value-ref="UserDataSource" key="User"></entry> 
  </map> 
 </property> 
 <property name="defaultTargetDataSource" ref="testDataSource" ></property> 
</bean> 

在这个配置中第一个property属性配置目标数据源,<map key-type="java.lang.String">中的key-type必须要和静态键值对照类DataSourceConst中的值的类型相 同;<entry key="User" value-ref="userDataSource"/>中key的值必须要和静态键值对照类中的值相同,如果有多个值,可以配置多个< entry>标签。第二个property属性配置默认的数据源。

动态切换是数据源

DataSourceContextHolder.setDataSourceType(DataSourceConst.TEST); 

该方案的优势

首先,这个方案完全是在spring的框架下解决的,数据源依然配置在spring的配置文件中,sessionFactory依然去配置它的dataSource属性,它甚至都不知道dataSource的改变。唯一不同的是在真正的dataSource与sessionFactory之间增加了一个MultiDataSource。

其次,实现简单,易于维护。这个方案虽然我说了这么多东西,其实都是分析,真正需要我们写的代码就只有MultiDataSource、SpObserver两个类。MultiDataSource类真正要写的只有getDataSource()getDataSource(sp)两个方法,而SpObserver类更简单了。实现越简单,出错的可能就越小,维护性就越高。

最后,这个方案可以使单数据源与多数据源兼容。这个方案完全不影响BUS和DAO的编写。如果我们的项目在开始之初是单数据源的情况下开发,随着项目的进行,需要变更为多数据源,则只需要修改spring配置,并少量修改MVC层以便在请求中写入需要的数据源名,变更就完成了。如果我们的项目希望改回单数据源,则只需要简单修改配置文件。这样,为我们的项目将增加更多的弹性。

该方案的缺点

没有能够解决多用户访问单例“sessionFactory”时共享“dataSource”变量,导致产生争抢“dataSource”的结果,本质类似于操作系统中的“生产者消费者”问题。因此当多用户访问时,多数据源可能会导致系统性能下降的后果。

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

更多精彩内容其他人还在看

Java的面向对象编程基本概念学习笔记整理

这篇文章主要介绍了Java的面向对象编程基本概念学习笔记整理,包括类与方法以及多态等支持面向对象语言中的重要特点,需要的朋友可以参考下
收藏 0 赞 0 分享

Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法

这篇文章主要介绍了Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法 的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

基于Java实现杨辉三角 LeetCode Pascal's Triangle

这篇文章主要介绍了基于Java实现杨辉三角 LeetCode Pascal's Triangle的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Java中Spring获取bean方法小结

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢?下面通过本文给大家介绍Java中Spring获取bean方法小结,对spring获取bean方法相关知识感兴趣的朋友一起学习吧
收藏 0 赞 0 分享

如何计算Java对象占用了多少空间?

在Java中没有sizeof运算符,所以没办法知道一个对象到底占用了多大的空间,但是在分配对象的时候会有一些基本的规则,我们根据这些规则大致能判断出来对象大小,需要的朋友可以参考下
收藏 0 赞 0 分享

剖析Java中的事件处理与异常处理机制

这篇文章主要介绍了Java中的事件处理与异常处理机制,讲解Java是如何对事件或者异常作出响应以及定义异常的一些方法,需要的朋友可以参考下
收藏 0 赞 0 分享

详解Java的Struts2框架的结构及其数据转移方式

这篇文章主要介绍了详解Java的Struts2框架的结构及其数据转移方式,Struts框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
收藏 0 赞 0 分享

Java封装好的mail包发送电子邮件的类

本文给大家分享了2个java封装好的mail包发送电子邮件的类,并附上使用方法,小伙伴们可以根据自己的需求自由选择。
收藏 0 赞 0 分享

在Java的Struts中判断是否调用AJAX及用拦截器对其优化

这篇文章主要介绍了在Java的Struts中判断是否调用AJAX及用拦截器对其优化的方法,Struts框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
收藏 0 赞 0 分享

java多线程Future和Callable类示例分享

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。今天我们就来研究下Future和Callab
收藏 0 赞 0 分享
查看更多