`

spring 多数据库支持,动态切换数据库

阅读更多

为了备份特将此新的发到博客当中以备查找。

数据库的动态切换在很多项目当中都有应用,经我查阅了多篇文档,整合思路最终成功实现数据源的动态切换功能,并稳定运行了一段时间未发现异常。

 

我的数据源切换时根据域名并配合spring来切换的,不同的域名访问不同的数据源,当然可以根据其他的需求进行动态切换。

 

首先需要配置一个过滤器来过滤域名,并动态切换数据源。

web.xml 增加如下代码:

     <!-- 根据域名动态切换数据源 -->
     <filter>
    	<filter-name>ServerFilter</filter-name>
    	<filter-class>com.wfy.filter.ServerFilter</filter-class>
    </filter>
    <filter-mapping>
    	<filter-name>ServerFilter</filter-name>
    	<url-pattern>/*</url-pattern>
    </filter-mapping>

 

对应写入相应的java类:

package com.wfy.filter;

import java.io.File;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import com.wfy.multiData.SpObserver;

public class ServerFilter extends HttpServlet implements Filter {

	private static final long serialVersionUID = 6452049924844786456L;
	private static FilterConfig filterConfig;
	public void destroy() {
		// TODO Auto-generated method stub

	}
	public void init(FilterConfig filterConfig) throws ServletException
	{
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws IOException, ServletException {
		/**
		 * 需要在此处操作数据源,将数据源切换到新定义好的数据源当中。
		 */
		
		System.out.println("request.getServerName():_"+request.getServerName());
		String url = Thread.currentThread().getContextClassLoader().getResource("") + "dataSource/_"+request.getServerName()+".xml";
		File f=new File(url.substring(6, url.length()));
		//确认数据源配置文件存在,切换数据源
		if(f.exists()){
			SpObserver.putSp("_"+request.getServerName());
		}else{
		//如果数据源配置文件不存在,使用默认数据源
			SpObserver.putSp("_dataSource");
		}
		
		filterChain.doFilter(request, response);
	}
}

 

SpObserver类:

package com.wfy.multiData;

/**
 * @author 金鑫
 *
 */
public class SpObserver {
	private static ThreadLocal local = new ThreadLocal();

	public static void putSp(String sp) {
		local.set(sp);
	}

	public static String getSp() {
		return (String)local.get();
	}
}

  这样过滤器的设置就算完成了,下面是spring的设置

spring配置文件:

	<!-- 数据库模块 初始化 -->
	<bean id="DynamicLoadBean" class="com.wfy.multiData.DynamicLoadBean" />
	<!--可以通过他动态增加新的数据源-->
	<bean id="InitDataSource" class="com.wfy.init.InitDataSource"></bean>

	<!--配置统一数据源,将来系统中使用的数据源将从他当中获取-->
	<bean id="DataSource" class="com.wfy.multiData.MultiDataSource">
		<property name="dataSource">  
			<ref bean="_dataSource" />  
		</property>  
	</bean>

 

MultiDataSource类:

package com.wfy.multiData;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.wfy.exceptionAdvisor.BusinessException;

/**
 * @author 金鑫
 *
 */
public class MultiDataSource implements DataSource,ApplicationContextAware {

	private static final Log log = LogFactory.getLog(MultiDataSource.class);
	private ApplicationContext applicationContext = null;
	private DataSource dataSource = null;
	/* (non-Javadoc)
	 * @see javax.sql.DataSource#getConnection()
	 */
	public Connection getConnection() throws SQLException {
		return getDataSource().getConnection();
	}

	/* (non-Javadoc)
	 * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String)
	 */
	public Connection getConnection(String arg0, String arg1)
			throws SQLException {
		return getDataSource().getConnection(arg0, arg1);
	}

	/* (non-Javadoc)
	 * @see javax.sql.DataSource#getLogWriter()
	 */
	public PrintWriter getLogWriter() throws SQLException {
		return getDataSource().getLogWriter();
	}

	/* (non-Javadoc)
	 * @see javax.sql.DataSource#getLoginTimeout()
	 */
	public int getLoginTimeout() throws SQLException {
		return getDataSource().getLoginTimeout();
	}

	/* (non-Javadoc)
	 * @see javax.sql.DataSource#setLogWriter(java.io.PrintWriter)
	 */
	public void setLogWriter(PrintWriter arg0) throws SQLException {
		getDataSource().setLogWriter(arg0);
	}

	/* (non-Javadoc)
	 * @see javax.sql.DataSource#setLoginTimeout(int)
	 */
	public void setLoginTimeout(int arg0) throws SQLException {
		getDataSource().setLoginTimeout(arg0);
	}

	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
	
	public DataSource getDataSource(String dataSourceName){
		log.debug("dataSourceName:"+dataSourceName);
		try{
			if(dataSourceName==null||dataSourceName.equals("")){
				return this.dataSource;
			}
			return (DataSource)this.applicationContext.getBean(dataSourceName);
		}catch(NoSuchBeanDefinitionException ex){
			throw new BusinessException("没有 <name:"+dataSourceName+"> 数据源 在系统当中!");
		}
	}
	
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public DataSource getDataSource(){
		String sp = SpObserver.getSp();
		return getDataSource(sp);
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}
}

 

DynamicLoadBean类:

package com.wfy.multiData;

import java.io.IOException;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.ResourceEntityResolver;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;

/**
 * 使用方法loadBean()向spring的beanFactory动态地装载bean,该方法的参数configLocationString等同于
 * spring配置中的contextConfigLocation,同样支持诸如"/WEB-INF/ApplicationContext-*.xml"的写法。
 * @author FanGang
 *
 */
public class DynamicLoadBean implements ApplicationContextAware{

	private XmlWebApplicationContext applicationContext = null;
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = (XmlWebApplicationContext)applicationContext;
	}
	public XmlWebApplicationContext getApplicationContext() {
		return applicationContext;
	}
	
	/**
	 * 向spring的beanFactory动态地装载bean
	 * @param configLocationString 要装载的bean所在的xml配置文件位置。
	 */
	public void loadBean(String configLocationString){
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry)getApplicationContext().getBeanFactory());
		beanDefinitionReader.setResourceLoader(getApplicationContext());
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(getApplicationContext()));
		try {
			String[] configLocations = new String[]{configLocationString};
			for(int i=0;i<configLocations.length;i++){
				System.out.println(configLocations[i]);
				beanDefinitionReader.loadBeanDefinitions(getApplicationContext().getResources(configLocations[i]));
			}	
		} catch (BeansException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

InitDataSource类(如果在系统运行的时候需要动态增加数据源的话可以调用此类来执行):

package com.wfy.init;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;


import com.wfy.multiData.DynamicLoadBean;

public class InitDataSource implements ApplicationContextAware {
	private ApplicationContext applicationContext = null;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	public void init(String url){
		DynamicLoadBean dynamicLoadBean = (DynamicLoadBean)this.applicationContext.getBean("DynamicLoadBean");
		dynamicLoadBean.loadBean("classpath:dataSource/"+ url +".xml");
	}
}

 这样基本数据源配置就算完成了,在系统运行当时就可以根据不同的域名(连接地址)来动态的切换数据库了。

 

另外我的数据源配置文件是单独保存在一个文件夹当中的,这样服务在启动的时候就会动态的去加载这些数据源了

比如:

我的数据源文件是存放处classpath:dataSource文件夹里面,

那我的文件夹下面就会有很多的类似文件名的xml文件:_192.168.234.250.xml,_dataSource.xml(必须配置,默认数据源文件),_wfyerp.gnway.net.xml,然后在系统启动的时候就会去动态加载这些文件了。

如:当我们访问的地址是:http://wfyerp.gnway.net 这个网址的时候,实际数据库访问的将会是_wfyerp.gnway.net.xml文件中的数据源。

现在贴上这些配置文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<bean id="_wfyerp.gnway.net" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"></property>
		<property name="url" value="jdbc:sqlserver://192.168.234.234:1433;databaseName=fy_erp_v6"></property>
		<property name="username" value="sa"></property>
		<property name="password" value="wfyerp2005"></property>
	</bean>
</beans>

 

然后会了能让spring在启动的时候加载这些配置文件,我们需要修改web.xml文件来让他启动的时候加载他们

web.xml修改spring配置如下:

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml, (classpath:dataSource/*.xml 需要新增的配置信息)</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

 

文件内打括号的部分为新增的配置信息,其他跟默认不改变即可。

 

到此我们通过spring+过滤器 来动态切换数据源的问题就得到圆满解决了。

 

另附样例一个,导入spring2.5的包,然后index.jsp是演示不同数据源的效果,大家稍加改用几个,需要修改的地方有:

数据库连接,已经域名地址,如我的ip地址为:192.168.234.250 所以我的数据源配置文件就包含了这个文件,然后包含了localhost文件,这样就能看出数据源切换的效果来了。

5
1
分享到:
评论
9 楼 jinyanhui2008 2012-11-09  
hzq20100521 写道
你好,我的需求这个有点不一样,我的是系统启动的时候是连接的默认数据库,然后用户登录的时候,去判断这个用户应该连接的数据库,进行切换,网上搜了不少资料发现都没有可行,不晓得博主有没有做过这样的需求,我的邮箱francis.hu.0115@gmail.com,谢谢,静听佳音

我写的是可行的,甚至如果你在用户请求的时候动态创建数据库连接都没问题,只要你能忍受那个速度。
我写的其实是系统启动的时候没有连接任何数据库,但是在用户访问的时候才动态分配用户去连接那个数据库。
我想你的场景是否是使用默认数据库为系统初始化一些数据然后在切换数据库呢?其实这个完全是可以实现的,在MultiDataSource里面做些改造就能实现。
8 楼 hzq20100521 2012-10-30  
你好,我的需求这个有点不一样,我的是系统启动的时候是连接的默认数据库,然后用户登录的时候,去判断这个用户应该连接的数据库,进行切换,网上搜了不少资料发现都没有可行,不晓得博主有没有做过这样的需求,我的邮箱francis.hu.0115@gmail.com,谢谢,静听佳音
7 楼 jinyanhui2008 2012-02-22  
赵武艺 写道
您好,如果在系统运行时动态增加数据源,怎么调用InitDataSource这个类,是交给spring,还是new 一个InitDataSource的实例?谢谢!

不需要new一个的。
6 楼 赵武艺 2012-02-22  
您好,如果在系统运行时动态增加数据源,怎么调用InitDataSource这个类,是交给spring,还是new 一个InitDataSource的实例?谢谢!
5 楼 JetMah 2011-01-17  
如果是相同站点的话,不同数据源用户的Session怎样分开?现在这样的话是共用同样的Session的。
4 楼 anckey 2009-10-12  
谢谢,有项目用到,不过也是根据需求作出修改。。
3 楼 gotohometown 2009-08-26  
感谢,我也有类似的需求,通过session来判断具体的数据源。
先研究下
2 楼 jinyanhui2008 2009-07-17  
linvar 写道
不错,刚好有这个需求.
不过我的是根据不同的客户端
访问不同的数据源.

如果这样子的话可以通过session来判断,不同的session来调用不同的数据源,因为我的项目是flex的,并不存在session这个概念,所以只能那么使用了
1 楼 linvar 2009-07-06  
不错,刚好有这个需求.
不过我的是根据不同的客户端
访问不同的数据源.

相关推荐

    spring 数据库动态切换

    总之,Spring的数据库动态切换功能通过抽象化DataSource路由,实现了在运行时根据业务逻辑或环境条件灵活切换数据库的能力。这一特性大大增强了应用程序的灵活性和可扩展性。通过深入学习和实践,你可以将其应用于...

    Spring系统多数据库动态切换,完整demo直接使用

    在Spring MVC和Spring Data JPA框架中,实现多数据库动态切换是一项常见的需求,尤其是在大型分布式系统中。这个压缩包提供了一个完整的示例(demo),帮助开发者理解和应用这一功能。下面将详细讲解如何在Spring...

    Spring+Hibernate下的数据库连接动态切换

    在开发多租户或多数据库环境的应用系统时,往往需要实现动态切换数据库连接的功能。本文档将详细探讨如何在Spring与Hibernate框架下实现数据库连接的动态切换。该功能允许用户在登录时选择或输入特定的数据库名称,...

    Springcloud 多数库 多数据源整合,查询动态切换数据库

    总的来说,Spring Cloud多数据源整合和动态切换数据库是一项挑战性的工作,但通过合理的架构设计和Spring框架的特性,可以有效地实现这一功能,为大型分布式系统提供灵活和可扩展的数据访问能力。

    spring 动态切换数据库

    在Spring框架中,动态切换数据库是一项重要的功能,它允许应用程序根据特定条件或需求在运行时灵活地连接到不同的数据库。这种能力在多租户环境、数据隔离或测试环境中尤其有用。接下来,我们将深入探讨实现这一功能...

    Spring 数据库动态切换

    数据库的动态切换在很多项目当中都有应用,经我查阅了多篇文档,整合思路最终成功实现数据源的动态切换功能,并稳定运行了一段时间未发现异常。 我的数据源切换时根据域名并配合spring来切换的,不同的域名访问...

    spring多数据库

    在多数据库切换查询中,`@Profile`注解可以帮助我们在不同环境(如开发、测试、生产)之间切换数据库配置。例如,你可以为每个环境创建一个配置类,并用`@Profile("dev")`、`@Profile("test")`和`@Profile("prod")`...

    springboot数据库连接动态切换源代码

    在Spring Boot应用中,数据库连接动态切换是一种常见的需求,尤其在多租户或者有不同业务场景的系统中。本项目提供了实现这一功能的源代码,允许根据不同的用户操作或HTTP请求来选择不同的数据库,而无需修改...

    springboot通过数据库动态连接多数据库

    在Spring Boot应用中,动态连接多数据库是一种常见的需求,尤其在构建分布式系统或者需要支持多种数据源的场景下。Spring Boot以其简洁的配置和强大的自动配置能力,使得处理这种复杂性变得相对简单。本篇文章将深入...

    java hibernate不同数据库之间的动态切换

    然而,在某些情况下,我们可能需要在运行时根据不同的条件或需求动态地切换数据库,比如在测试环境和生产环境中使用不同的数据库。这个过程就称为“动态切换数据库”。在本文中,我们将深入探讨如何在Java Hibernate...

    springboot整合redis动态切换每个数据库

    springboot整合redis动态切换每个数据库,

    SpringBoot整合Sharding-JDBC,实现从数据库加载sharding-jdbc数据源,实现多种数据库数据源切换,数据库方言动态切换

    这可以通过监听数据库表的变化,获取最新的数据源配置,然后通过Spring的`DataSourceProxy`或`AbstractRoutingDataSource`实现动态数据源切换。 3. **数据库方言动态切换** Sharding-JDBC支持多种数据库,如MySQL...

    基于springboot的多数据库动态切换

    在现代企业级应用开发中,...通过配置不同的数据源、自定义注解和AOP切面,我们可以轻松地实现在运行时动态切换数据库,满足各种复杂业务需求。在实际开发中,还需要考虑性能优化、错误处理和代码的可维护性等因素。

    spring多数据源动态切换方案

    "Spring多数据源动态切换方案"是解决这一问题的关键技术,它允许应用程序根据业务需求动态选择数据源,提高了系统的灵活性和可扩展性。下面我们将详细探讨如何在Spring中实现多数据源的配置及动态切换。 首先,我们...

    Spring.Net,Nhibernate多数据库操作

    在IT行业中,Spring.Net和NHibernate是两个非常重要的开源框架,...你可以根据实际需求调整数据库配置、SessionFactory设置,以及业务逻辑中的数据库切换逻辑,确保应用程序能够高效、稳定地运行在多种数据库环境之下。

    Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源

    在IT行业中,构建大型分布式系统时,数据源的动态切换是一项关键能力,它允许系统根据业务需求选择不同的数据库进行操作。本项目“Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源”正是针对这一需求...

    springboot数据库连接动态切换源代码.zip

    这通常在多租户系统、数据隔离或者需要在不同环境(如开发、测试、生产)之间切换数据库的情况下非常有用。本项目提供了一套完整的源代码实现,帮助开发者理解并应用这一技术。 首先,Spring Boot通过`spring-boot-...

    JEECG切换数据库方法

    在进行JEECG切换数据库时,支持多种主流数据库系统,例如ORACLE、MySQL和Microsoft SQL Server等。下面将详细阐述JEECG平台切换数据库的具体操作步骤及其背后涉及的相关知识点。 首先,了解数据库配置文件的重要性...

    SpringBoot使用注解实现 Redis 数据库的切换.zip

    在实际项目中,我们可能需要根据特定的条件动态切换数据库。这时,可以创建一个工具类,提供一个方法接收数据库编号,并返回对应的`RedisTemplate`: ```java @Component public class RedisUtil { @Autowired ...

Global site tag (gtag.js) - Google Analytics