Spring实现动态切换多数据源的解决方案
作者:nevergiveupzeng 发布时间:2023-05-21 13:07:15
前言
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”的结果,本质类似于操作系统中的“生产者消费者”问题。因此当多用户访问时,多数据源可能会导致系统性能下降的后果。
来源:http://www.cnblogs.com/zengda/p/4500684.html?utm_source=tuicool
猜你喜欢
- 今天做了一个java对象转Map的例子,执行的时候报错了,如下:Exception in thread "main" j
- 1. 简单说明嗨,大家好!今天给大家分享的是Mybatis-plus 插件的分页机制,说起分页机制,相信我们程序员都不陌生,今天,我就给大家
- 在java的开发中,java开发人员建议,尽量少用内部类,要把内部类提出他所处的那个类,单独生成一个类。直接来代码:package com.
- 前言 短时间提升自己最快的手段就是背面试题,最近总结了Java常用的面试题,分享给大家,希望大家都能圆梦大厂,加油,我命由我不由天
- RestTemplate设计是为了Spring更好的请求并解析Restful风格的接口返回值而设计的,通过这个类可以在请求接口时直接解析对应
- 本文实例为大家分享了C语言实现两个矩阵相乘的具体代码,供大家参考,具体内容如下程序功能:实现两个矩阵相乘的C语言程序,并将其输出代码如下:#
- 一、Mybatis1、mybatis-config.xml<?xml version="1.0" encoding
- 1.取整运算符取整从字面意思理解就是被除数到底包含几个除数,也就是能被整除多少次,那么它有哪些需要注意的地方呢?先看下面的两端代码: &nb
- 一、问题重现1.配置文件spring: #DataSource数据源 datasource: &nbs
- 环境:eclipse + spring mvc + maven1、直接看图,把数据库的配置单独拿出来放在了resources_env目录下,
- 一个项目中需要使用两个数据库,Oracle 和Mysql,于是参考各个blog,实现此功能。写好后才发现,原来的事务失效了,我去...spr
- 报错信息:java.lang.Exception: org.apache.hadoop.mapreduce.task.reduce.Shuf
- 最近在看《.NET游戏编程入门经典 C#篇》 第一章介绍了如何制作俄罗斯方块,自己试了试按照书上的步骤,可算是完成了。于是写下这篇文章留作纪
- 用Stream解决两层List属性求和假设一个人有很多个银行账户,每个银行账户中存有不同金额的存款,那么我们如何用Stream求一组人的所有
- 每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“引用”。在 JDK.1.2 之后
- 读取文件流时,经常会遇到乱码的现象,造成乱码的原因当然不可能是一个,这里主要介绍因为文件编码格式而导致的乱码的问题。首先,明确一点,文本文件
- 静态代理: 由我们开发者自己手动创建或者在程序运行前就已经存在的代理类,静态代理通常只代理一个类, * 是代理一个接口下的多个实现类。动态
- 一、文件的编码package com.study.io;/*** 测试文件编码*/public class EncodeDemo {/***
- 同步代码块基本语句synchronized (任意对象) {操作共享代码}代码示例public class SellTicket imple
- 本文将通过阅读spring源码,分析@ComponentScan注解扫描组件的原理。和@Bean注解一样,@ComponentScan注解也