深入理解spring多数据源配置

项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和hibernate的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作。

正如上图所示,每一块都是指定绑死的,如果是多个数据源,也只能是下图中那种方式。

可看出在Dao层代码中写死了两个SessionFactory,这样日后如果再多一个数据源,还要改代码添加一个SessionFactory,显然这并不符合开闭原则。

那么正确的做法应该是

代码如下:

1. applicationContext.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:aop="http://www.springframework.org/schema/aop"
  xmlns:cache="http://www.springframework.org/schema/cache"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
  xmlns:jms="http://www.springframework.org/schema/jms" xmlns:lang="http://www.springframework.org/schema/lang"
  xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:oxm="http://www.springframework.org/schema/oxm"
  xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task"
  xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
  http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
  http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
  http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd
  http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
  http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd
  http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd"> 

  <context:annotation-config /> 

  <context:component-scan base-package="com"></context:component-scan> 

  <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
      <list>
        <value>classpath:com/resource/config.properties</value>
      </list>
    </property>
  </bean> 

  <bean id="dataSourceOne" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">
    <property name="driverClass" value="${dbOne.jdbc.driverClass}" />
    <property name="jdbcUrl" value="${dbOne.jdbc.url}" />
    <property name="user" value="${dbOne.jdbc.user}" />
    <property name="password" value="${dbOne.jdbc.password}" />
    <property name="initialPoolSize" value="${dbOne.jdbc.initialPoolSize}" />
    <property name="minPoolSize" value="${dbOne.jdbc.minPoolSize}" />
    <property name="maxPoolSize" value="${dbOne.jdbc.maxPoolSize}" />
  </bean> 

  <bean id="dataSourceTwo" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">
    <property name="driverClass" value="${dbTwo.jdbc.driverClass}" />
    <property name="jdbcUrl" value="${dbTwo.jdbc.url}" />
    <property name="user" value="${dbTwo.jdbc.user}" />
    <property name="password" value="${dbTwo.jdbc.password}" />
    <property name="initialPoolSize" value="${dbTwo.jdbc.initialPoolSize}" />
    <property name="minPoolSize" value="${dbTwo.jdbc.minPoolSize}" />
    <property name="maxPoolSize" value="${dbTwo.jdbc.maxPoolSize}" />
  </bean> 

  <bean id="dynamicDataSource" class="com.core.DynamicDataSource">
    <property name="targetDataSources">
      <map key-type="java.lang.String">
        <entry value-ref="dataSourceOne" key="dataSourceOne"></entry>
        <entry value-ref="dataSourceTwo" key="dataSourceTwo"></entry>
      </map>
    </property>
    <property name="defaultTargetDataSource" ref="dataSourceOne">
    </property>
  </bean> 

  <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dynamicDataSource" />
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
        <prop key="hibernate.show_sql">false</prop>
        <prop key="hibernate.format_sql">true</prop>
        <prop key="hbm2ddl.auto">create</prop>
      </props>
    </property>
    <property name="packagesToScan">
      <list>
        <value>com.po</value>
      </list>
    </property>
  </bean> 

  <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
  </bean> 

  <aop:config>
    <aop:pointcut id="transactionPointCut" expression="execution(* com.dao..*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointCut" />
  </aop:config> 

  <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
      <tx:method name="add*" propagation="REQUIRED" />
      <tx:method name="save*" propagation="REQUIRED" />
      <tx:method name="update*" propagation="REQUIRED" />
      <tx:method name="delete*" propagation="REQUIRED" />
      <tx:method name="*" read-only="true" />
    </tx:attributes>
  </tx:advice> 

  <aop:config>
    <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor">
      <aop:pointcut id="daoOne" expression="execution(* com.dao.one.*.*(..))" />
      <aop:pointcut id="daoTwo" expression="execution(* com.dao.two.*.*(..))" />
      <aop:before pointcut-ref="daoOne" method="setdataSourceOne" />
      <aop:before pointcut-ref="daoTwo" method="setdataSourceTwo" />
    </aop:aspect>
  </aop:config>
</beans>

2. DynamicDataSource.class

package com.core; 

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 

public class DynamicDataSource extends AbstractRoutingDataSource{ 

  @Override
  protected Object determineCurrentLookupKey() {
    return DatabaseContextHolder.getCustomerType();
  } 

}

3. DatabaseContextHolder.class

package com.core; 

public class DatabaseContextHolder { 

  private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 

  public static void setCustomerType(String customerType) {
    contextHolder.set(customerType);
  } 

  public static String getCustomerType() {
    return contextHolder.get();
  } 

  public static void clearCustomerType() {
    contextHolder.remove();
  }
}

4. DataSourceInterceptor.class

package com.core; 

import org.aspectj.lang.JoinPoint;
import org.springframework.stereotype.Component; 

@Component
public class DataSourceInterceptor { 

  public void setdataSourceOne(JoinPoint jp) {
    DatabaseContextHolder.setCustomerType("dataSourceOne");
  } 

  public void setdataSourceTwo(JoinPoint jp) {
    DatabaseContextHolder.setCustomerType("dataSourceTwo");
  }
}

5. po实体类

package com.po; 

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table; 

@Entity
@Table(name = "BTSF_BRAND", schema = "hotel")
public class Brand { 

  private String id;
  private String names;
  private String url; 

  @Id
  @Column(name = "ID", unique = true, nullable = false, length = 10)
  public String getId() {
    return this.id;
  } 

  public void setId(String id) {
    this.id = id;
  } 

  @Column(name = "NAMES", nullable = false, length = 50)
  public String getNames() {
    return this.names;
  } 

  public void setNames(String names) {
    this.names = names;
  } 

  @Column(name = "URL", length = 200)
  public String getUrl() {
    return this.url;
  } 

  public void setUrl(String url) {
    this.url = url;
  }
}
package com.po;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table; 

@Entity
@Table(name = "CITY", schema = "car")
public class City { 

  private Integer id; 

  private String name; 

  @Id
  @Column(name = "ID", unique = true, nullable = false)
  public Integer getId() {
    return id;
  } 

  public void setId(Integer id) {
    this.id = id;
  } 

  @Column(name = "NAMES", nullable = false, length = 50)
  public String getName() {
    return name;
  } 

  public void setName(String name) {
    this.name = name;
  }
}

6. BrandDaoImpl.class

package com.dao.one; 

import java.util.List; 

import javax.annotation.Resource; 

import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository; 

import com.po.Brand; 

@Repository
public class BrandDaoImpl implements IBrandDao { 

  @Resource
  protected SessionFactory sessionFactory; 

  @SuppressWarnings("unchecked")
  @Override
  public List<Brand> findAll() {
    String hql = "from Brand";
    Query query = sessionFactory.getCurrentSession().createQuery(hql);
    return query.list();
  }
}

7. CityDaoImpl.class

package com.dao.two; 

import java.util.List; 

import javax.annotation.Resource; 

import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository; 

import com.po.City; 

@Repository
public class CityDaoImpl implements ICityDao { 

  @Resource
  private SessionFactory sessionFactory; 

  @SuppressWarnings("unchecked")
  @Override
  public List<City> find() {
    String hql = "from City";
    Query query = sessionFactory.getCurrentSession().createQuery(hql);
    return query.list();
  }
}

8. DaoTest.class

package com.test; 

import java.util.List; 

import javax.annotation.Resource; 

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration; 

import com.dao.one.IBrandDao;
import com.dao.two.ICityDao;
import com.po.Brand;
import com.po.City; 

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:com/resource/applicationContext.xml")
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class DaoTest { 

  @Resource
  private IBrandDao brandDao; 

  @Resource
  private ICityDao cityDao; 

  @Test
  public void testList() {
    List<Brand> brands = brandDao.findAll();
    System.out.println(brands.size()); 

    List<City> cities = cityDao.find();
    System.out.println(cities.size());
  }
} 

利用aop,达到动态更改数据源的目的。当需要增加数据源的时候,我们只需要在applicationContext配置文件中添加aop配置,新建个DataSourceInterceptor即可。而不需要更改任何代码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring配置多个数据源并实现动态切换示例

    1.配置两个不同的数据源,如下(由于项目使用的是druid数据库连接,配置可以会复杂点比较): <!-- 数据源配置1 --> <bean id="testDataSource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name=&quo

  • spring mybatis多数据源实例详解

    同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还有平台下的游戏对应的数据库: 2)两个或多个数据库是master-slave的关系,比如有mysql搭建一个 master-master,其后又带有多个slave:或者采用MHA搭建的master-slave复制: 目前我所知道的 Spring 多数据源的搭建大概有两种方式,可以根据多数据源的情况进

  • springboot + mybatis配置多数据源示例

    在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构: 简要原理: 1)DatabaseType列出所有的数据源的key---key 2)DatabaseContextHolder是一个线程安全的DatabaseType容器,并提供了向其中设置和获取DatabaseType的方法 3)DynamicDataSource继承AbstractRoutingDataSource并重写其中的方法determineCurrentLookupKey(),在该方法中使用Da

  • Spring MVC Mybatis多数据源的使用实例解析

    项目需要从其他网站获取数据,因为是临时加的需求,在开始项目时没想到需要多数据源 于是百度了一下,发现只需要改动一下Spring 的applicationContext.xml文件和编写三个工具类就可以完美实现 applicationContext.xml <!-- 多数据源配置 --> <bean id="ds1" class="org.apache.commons.dbcp.BasicDataSource"> <property na

  • Spring MVC配置双数据源实现一个java项目同时连接两个数据库的方法

    前言 本文主要介绍的是关于Spring MVC配置双数据源实现一个java项目同时连接两个数据库的方法,分享出来供大家参考学习,下面来看看详细的介绍: 实现方法: 数据源在配置文件中的配置 <pre name="code" class="java"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.spring

  • Spring动态多数据源配置实例Demo

    最近由于咨询spring如何配置多数据源的人很多,一一回答又比较麻烦,而且以前的博文中的配置也是有问题,因此特此重新发布一个Demo给大家. Demo中共有两个数据源,即MySQL和Oracle,并已经进行简单测试,动态切换数据源是没有问题的,希望借此Demo能帮助到大家. Demo下载地址: Spring动态切换多数据源Demo:http://xiazai.jb51.net/201701/yuanma/dynamicDatasourceDemo_jb51.rar 另外我给些说明,阐述下多数据源

  • 深入理解spring多数据源配置

    项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此.多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源.例如在一个spring和hibernate的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作. 正如上图所示,每一块都是指定绑死的,如果是多个数据源,也只能是下图中那种方式. 可看出在Dao层代码中写死了两

  • Spring jndi数据源配置方法详解

    本文实例为大家分享了Spring jndi数据源配置代码,供大家参考,具体内容如下 xml配置: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver

  • spring多数据源配置实现方法实例分析

    本文实例讲述了spring多数据源配置实现方法.分享给大家供大家参考,具体如下: 在网上找到的配置多数据源的方法. 1.扩展 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource类 实现代码 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource exte

  • Spring多个数据源配置详解

    前言 在上篇文章讲到了如何配置单数据源,但是在实际场景中,会有需要配置多个数据源的场景,比如说,我们在支付系统中,单笔操作(包含查询.插入.新增)中需要操作主库,在批量查询或者对账单查询等对实时性要求不高的场景,需要使用读库来操作,依次来减轻数据库的压力.那么我们如何配置多数据源? 这里还是基于springboot应用的情况下,我们看一下怎么配置. 因为SpringBoot会实现自动配置,但是SpringBoot并不知道我们的业务场景分别要使用哪一个数据源,因此我们需要把相关的自动配置关闭. 首

  • spring注解 @PropertySource配置数据源全流程

    目录 @PropertySource数据源配置 使用xml配置数据源 使用javaBean配置数据源 @value注解读取配置 @PropertySource注解读取配置 注解的spring多数据源配置及使用 先看一下spring获取数据源的源码 第一步:创建一个DynamicDataSource的类 第二步:创建DynamicDataSourceHolder 第三步:配置多个数据源 @PropertySource数据源配置 一般在配置数据源是都会使用xml的方式注入,key-value在pro

  • 详解基于Spring Boot与Spring Data JPA的多数据源配置

    由于项目需要,最近研究了一下基于spring Boot与Spring Data JPA的多数据源配置问题.以下是传统的单数据源配置代码.这里使用的是Spring的Annotation在代码内部直接配置的方式,没有使用任何XML文件. @Configuration @EnableJpaRepositories(basePackages = "org.lyndon.repository") @EnableTransactionManagement @PropertySource("

  • 详解Spring Boot整合Mybatis实现 Druid多数据源配置

    一.多数据源的应用场景 目前,业界流行的数据操作框架是 Mybatis,那 Druid 是什么呢? Druid 是 Java 的数据库连接池组件.Druid 能够提供强大的监控和扩展功能.比如可以监控 SQL ,在监控业务可以查询慢查询 SQL 列表等.Druid 核心主要包括三部分: 1. DruidDriver 代理 Driver,能够提供基于 Filter-Chain 模式的插件体系. 2. DruidDataSource 高效可管理的数据库连接池 3. SQLParser 当业务数据量达

  • Spring Boot 2.0多数据源配置方法实例详解

    两个数据库实例,一个负责读,一个负责写. datasource-reader: type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://192.168.43.61:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false username: icbc password: icbc driver-class-na

  • Spring Boot+Jpa多数据源配置的完整步骤

    关于 有时候,随着业务的发展,项目关联的数据来源会变得越来越复杂,使用的数据库会比较分散,这个时候就会采用多数据源的方式来获取数据.另外,多数据源也有其他好处,例如分布式数据库的读写分离,集成多种数据库等等. 下面分享我在实际项目中配置多数据源的案例.话不多说了,来一起看看详细的介绍吧 步骤 1.application.yml文件中,配置数据库源.这里primary是主库,secondary是从库. server: port: 8089 # 多数据源配置 #primary spring: pri

随机推荐