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

 更新时间:2017年01月17日 11:20:13   作者:nevergiveupzeng  
这篇文章主要给大家介绍了Spring实现动态切换多数据源的解决方案,文中给出了详细的介绍和示例代码,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友可以参考学习,下面来一起看看吧。

前言

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实现文件上传至服务器的方法

    这篇文章主要为大家详细介绍了Java实现文件上传至服务器的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • Java并发中的ABA问题学习与解决方案

    Java并发中的ABA问题学习与解决方案

    这篇文章主要介绍了Java并发中的ABA问题学习与解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • MyBatis XML方式的基本用法之多表查询功能的示例代码

    MyBatis XML方式的基本用法之多表查询功能的示例代码

    这篇文章主要介绍了MyBatis XML方式的基本用法之多表查询功能的示例代码,本文通过示例文字相结合的形式给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • SpringBoot结合JWT实现用户登录、注册、鉴权

    SpringBoot结合JWT实现用户登录、注册、鉴权

    用户登录、注册及鉴权是我们基本所有系统必备的,也是很核心重要的一块,本文主要介绍了SpringBoot结合JWT实现用户登录、注册、鉴权,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2023-05-05
  • SSH框架网上商城项目第17战之购物车基本功能

    SSH框架网上商城项目第17战之购物车基本功能

    这篇文章主要为大家详细介绍了SSH框架网上商城项目第17战之购物车基本功能的实现过程,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Java的invoke方法的具体使用

    Java的invoke方法的具体使用

    本文主要介绍了Java的invoke方法的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • mybatisplus添加真正的批量新增、批量更新的实现

    mybatisplus添加真正的批量新增、批量更新的实现

    这篇文章主要介绍了mybatisplus添加真正的批量新增、批量更新的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • 利用Spring IOC技术实现用户登录验证机制

    利用Spring IOC技术实现用户登录验证机制

    这篇文章主要为大家详细介绍了Spring IOC技术实现用户登录验证机制的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Java项目向Maven迁移的实战示例

    Java项目向Maven迁移的实战示例

    本文主要介绍了Java项目向Maven迁移实战指南,提升自动化构建、依赖管理和项目信息管理的能力,具有一定的参考价值,感兴趣的可以了解一下
    2025-07-07
  • MybatisPlus 主键策略的几种实现方法

    MybatisPlus 主键策略的几种实现方法

    MybatisPlus-Plus支持多种主键生成策略,可以通过@TableId注解的type属性配置,主要策略包括AUTO、INPUT、ASSING_ID、ASSING_UUID和NONE,每种策略适用于不同的场景,下面就来介绍一下
    2024-10-10

最新评论