http://blog.csdn.net/qilin18/article/details/17614005
项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和hibernate的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作。
正如上图所示,每一块都是指定绑死的,如果是多个数据源,也只能是下图中那种方式。
可看出在Dao层代码中写死了两个SessionFactory,这样日后如果再多一个数据源,还要改代码添加一个SessionFactory,显然这并不符合开闭原则。
那么正确的做法应该是
先说一下我的思路:
首先做一个创建数据源配置文件的类,专门用于创建数据源xml配置,叫ConfigFileCreator.java
其次,编写一个动态加载刚才创建的配置文件的类,叫 DynamicLoadBean.java。至此,创建的数据源到内存中已经完成。
第三,重点编写这个DynamicDataSource.java,该类主要是用来实现动态切换数据源,并通知容器。在这一块我选择了修改,AbstractRoutingDataSource.java,编写一个支持添加数据源对象的方法public void addDataSource(Object key,Object dataSource)
第四,写例子来测试
实现过程如下:
1.bean.xml配置文件
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
- <!-- 自动扫描与装配bean -->
- <context:component-scan base-package="qilin"></context:component-scan>
- <!-- 使用外部的配置文件 -->
- <context:property-placeholder location="classpath:jdbc.properties" />
- <bean id="defaultDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <!-- 数据库连接信息 -->
- <property name="jdbcUrl" value="${jdbcUrl}"></property>
- <property name="driverClass" value="${driverClass}"></property>
- <property name="user" value="${username}"></property>
- <property name="password" value="${password}"></property>
- </bean>
- <bean id="dataSourceA" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <!-- 数据库连接信息 -->
- <property name="jdbcUrl" value="jdbc:mysql:///dynamictest"></property>
- <property name="driverClass" value="${driverClass}"></property>
- <property name="user" value="${username}"></property>
- <property name="password" value="${password}"></property>
- </bean>
- <bean id="dynamicdatasource" class="qilin.utils.DynamicDataSource">
- <property name="targetDataSources">
- <map key-type="java.lang.String">
- <entry key="defaultDataSource" value-ref="defaultDataSource" />
- <entry key="dataSourceA" value-ref="dataSourceA" />
- </map>
- </property>
- <property name="defaultTargetDataSource" ref="defaultDataSource" />
- </bean>
- <!-- 配置SessionFactory -->
- <bean id="sessionFactory"
- class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
- <property name="dataSource" ref="dynamicdatasource" />
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
- <prop key="hibernate.hbm2ddl.auto">none</prop>
- <prop key="hibernate.show_sql">true</prop>
- <prop key="hibernate.format_sql">false</prop>
- <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
- </props>
- </property>
- <!-- 注解方式配置 -->
- <property name="annotatedClasses">
- <list>
- <value>qilin.entity.Student</value>
- </list>
- </property>
- </bean>
- <!-- 配置声明式事务管理,采用基于注解的方式 -->
- <bean id="transactionManager"
- class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory" ref="sessionFactory"></property>
- </bean>
- <tx:annotation-driven transaction-manager="transactionManager" />
- <bean id="dynamicLoadBean" class="qilin.utils.DynamicLoadBean"></bean>
- </beans>
2.AbstractRoutingDataSource.class 修改的部分
- /**@author qilin**/
- public void addDataSource(Object key,Object dataSource){
- this.targetDataSources.put(key, dataSource);
- setTargetDataSources(this.targetDataSources);
- }
3.DynamicDataSource.class 这个类中有一个地方需要注意,当我们添加数据,切换了数据源,要通知当前spring容器,需要调用父类的super.afterPropertiesSet();方法
- package qilin.utils;
- import java.util.Map;
- import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
- import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
- public class DynamicDataSource extends AbstractRoutingDataSource {
- /*
- * 该方法必须要重写 方法是为了根据数据库标示符取得当前的数据库
- */
- @Override
- public Object determineCurrentLookupKey() {
- return DataSourceContextHolder.getDataSourceName();
- }
- @Override
- public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
- super.setDataSourceLookup(dataSourceLookup);
- }
- @Override
- public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
- super.setDefaultTargetDataSource(defaultTargetDataSource);
- }
- @Override
- public void setTargetDataSources(Map targetDataSources) {
- super.setTargetDataSources(targetDataSources);
- //重点
- super.afterPropertiesSet();
- }
- }
4.动态加载数据源配置文件DynamicLoadBean.class
- package qilin.utils;
- import java.io.IOException;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.config.BeanDefinition;
- import org.springframework.beans.factory.support.BeanDefinitionRegistry;
- import org.springframework.beans.factory.support.ChildBeanDefinition;
- import org.springframework.beans.factory.support.DefaultListableBeanFactory;
- 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.ConfigurableApplicationContext;
- /**
- * 动�?�加载数据源
- * @author qilin
- *
- */
- public class DynamicLoadBean implements ApplicationContextAware {
- private ConfigurableApplicationContext applicationContext = null;
- public void setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.applicationContext = (ConfigurableApplicationContext) applicationContext;
- }
- public ConfigurableApplicationContext getApplicationContext() {
- return applicationContext;
- }
- /**
- * 1.配置文件的位置固�?
- * 2.配置文件中bean的名字已�?
- * @param configLocationString
- */
- public void loadBean(String fileName)
- {
- XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry)getApplicationContext().getBeanFactory());
- beanDefinitionReader.setResourceLoader(getApplicationContext());
- beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(getApplicationContext()));
- try
- {
- beanDefinitionReader.loadBeanDefinitions(getApplicationContext().getResources(fileName));
- } catch (BeansException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void registBean(String beanName, String parentName) {
- DefaultListableBeanFactory fcy = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
- BeanDefinition beanDefinition = new ChildBeanDefinition(parentName);
- fcy.registerBeanDefinition(beanName, beanDefinition);
- }
- }
5.DataSourceContextHolder.class
- package qilin.utils;
- public class DataSourceContextHolder {
- private static final ThreadLocal contextHolder=new ThreadLocal();
- public static void setDataSourceType(String dataSourceName){
- contextHolder.set(dataSourceName);
- }
- public static String getDataSourceName(){
- return (String) contextHolder.get();
- }
- public static void clearDataSourceType(){
- contextHolder.remove();
- }
- }
5.测试代码
- package junit;
- import java.util.HashMap;
- import java.util.Map;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.mchange.v2.c3p0.ComboPooledDataSource;
- import qilin.entity.Student;
- import qilin.service.StuService;
- import qilin.utils.DataSourceContextHolder;
- import qilin.utils.DynamicDataSource;
- import qilin.utils.DynamicLoadBean;
- public class Test {
- public static void main(String[] args) {
- ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
- StuService stuService = (StuService) ac.getBean("stuServiceImpl");
- Student stu = new Student();
- stu.setStuName("qilin");
- stuService.save(stu);
- DataSourceContextHolder.setDataSourceType("dataSourceA");
- Student _stu = new Student();
- _stu.setStuName("_qilin1");
- stuService.save(_stu);
- //创建一个数据源
- DynamicLoadBean dynamicBeanLoad =(DynamicLoadBean)ac.getBean("dynamicLoadBean");
- dynamicBeanLoad.loadBean("classpath:mos/qqq.xml");
- ComboPooledDataSource dataSource = (ComboPooledDataSource) ac.getBean("qqq");
- System.err.println(dataSource.getDriverClass());
- DynamicDataSource dynamicDataSource = (DynamicDataSource) ac.getBean("dynamicdatasource");
- // Map<String, ComboPooledDataSource> targetDataSources = new HashMap<String, ComboPooledDataSource>();
- // targetDataSources.put("qqq", dataSource);
- // Map<Object, Object> targetDataSources = dynamicDataSource.getTargetDataSources();
- // targetDataSources.put("qqq", dataSource);
- // dynamicDataSource.setTargetDataSources(targetDataSources);
- // dynamicDataSource.setDefaultTargetDataSource(dataSource);
- dynamicDataSource.addDataSource("qqq", dataSource);
- DataSourceContextHolder.setDataSourceType("qqq");
- Student __stu = new Student();
- __stu.setStuName("qilin2");
- stuService.save(__stu);
- }
- }
切换数据源就一句话搞定 DataSourceContextHolder.setDataSourceType("qqq");
下载链接http://download.csdn.net/detail/qi_lin70/6778247
相关推荐
本主题聚焦于在Spring Cloud环境中实现多数据库和多数据源的整合,并且能够动态切换查询的数据库。这是一个复杂但至关重要的需求,特别是在大型企业级应用中,可能需要根据业务逻辑或用户权限连接到不同的数据库。 ...
综上所述,Spring动态切换数据源是通过配置不同数据源,结合`AbstractRoutingDataSource`子类和`ThreadLocal`管理的策略,实现在运行时选择合适的数据源执行SQL操作。这一机制极大地增强了系统的灵活性和可扩展性。
Spring Boot配置动态数据源访问多个数据库实现代码详解 通过Spring Boot配置动态数据源访问多个数据库可以实现数据库的动态增删和数量无限的支持,下面将详细介绍该实现代码的知识点。 数据源配置管理 在Spring ...
总的来说,Spring Boot多数据源的配置涉及了Spring Boot的自动配置、数据源的创建与切换、事务管理的定制等多个方面。掌握这些知识点有助于构建更加复杂和灵活的分布式系统。通过学习和实践提供的源码,开发者能够更...
例如,我们可以使用`org.springframework.jdbc.datasource.DriverManagerDataSource`或Apache的`BasicDataSource`来创建数据源。 ```java @Configuration public class DataSourceConfig { @Bean(name = ...
支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。支持 自定义注解 ,需继承DS(3.2.0+)。提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi...
"Spring动态切换datasource实现mysql多主多从"是针对大型分布式系统中数据读写分离、负载均衡的一种常见策略。该技术使得应用程序能够在运行时根据业务需求灵活地选择不同的数据源,从而提高系统的可扩展性和可用性...
开发者可以创建多个 `DataSource` 实例,并通过 `@Primary` 或 `@Qualifier` 注解来指定主要数据源或在需要时注入特定数据源。`SpringBoot` 的 `AbstractRoutingDataSource` 类可以进一步帮助我们动态切换数据源,...
Spring Boot提供了AbstractRoutingDataSource类,它可以动态地根据上下文信息(比如事务或者注解)决定使用哪个数据源。我们可以创建一个继承自AbstractRoutingDataSource的自定义数据源类,并重写...
1. **配置数据源**:Spring提供了AbstractDataSource类作为抽象基类,我们可以通过实现它或者直接使用已有的实现如DataSourceTransactionManager来创建数据源。每个数据源需要配置连接池(如Druid、HikariCP)、...
本篇文章将探讨如何在Spring Boot中利用JPA(Java Persistence API)和JdbcTemplate来实现多数据源的管理,同时使用HikariCP作为高效的数据源连接池。 首先,让我们理解一下关键概念: 1. **Spring Boot**: 它是...
3. **配置数据源切换**:在 Spring Boot 的配置类中,使用 `@ConfigurationProperties` 注解加载上述配置,并通过 `@Bean` 创建 `DataSource` 实例。然后,可以使用 `@Primary` 标记主数据源,其他为辅助数据源。...
这可以通过文件系统、网络或任何其他数据源完成。例如,我们可以使用`java.io.File`类来定位本地文件系统中的jar文件。 3. **读取jar文件**:使用`java.util.jar.JarFile`类打开jar文件,并遍历其中的条目。每个...
但在某些场景下,如云环境或多租户系统,我们可能需要根据业务需求动态加载数据源。这可以通过监听数据库表的变化,获取最新的数据源配置,然后通过Spring的`DataSourceProxy`或`AbstractRoutingDataSource`实现动态...
在SpringMVC中配置多个数据源,我们通常会使用Spring的`AbstractRoutingDataSource`或`AbstractDataSource`。这个抽象类可以动态地决定使用哪个数据源,从而实现数据源的切换。在DEMO中,可能是通过实现`...
为了实现多数据源动态切换,项目可能使用了Spring的`AbstractRoutingDataSource`类。这是一个抽象数据源,可以根据当前上下文条件(如线程绑定的属性或环境变量)来决定使用哪个实际的数据源。开发者需要自定义`...
在Spring框架中,配置多个数据源并实现动态切换是一项常见的需求,特别是在大型系统中,可能需要连接到不同的数据库以满足不同业务场景的需求。本篇文章将详细介绍如何在Spring中配置两个不同的数据源,并实现它们...
标题中的"proxool 多数据源动态切换"指的是在Java应用程序中使用Proxool作为连接池,实现数据库连接的动态切换。Proxool是Apache软件基金会的一个开源项目,它提供了一个灵活、轻量级的数据库连接池解决方案。多数据...
这些信息通常会写入到不同的配置文件,如`db1.properties`和`db2.properties`,或者使用Spring框架的`@ConfigurationProperties`注解动态加载。 2. **构建DataSource**:使用Apache Commons DBCP、C3P0或HikariCP等...