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

由于项目需要,最近研究了一下基于spring Boot与Spring Data JPA的多数据源配置问题。以下是传统的单数据源配置代码。这里使用的是Spring的Annotation在代码内部直接配置的方式,没有使用任何XML文件。

@Configuration
@EnableJpaRepositories(basePackages = "org.lyndon.repository")
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class JpaConfig { 

  private static final String DATABASE_DRIVER = "db.driver";
  private static final String DATABASE_URL = "db.url";
  private static final String DATABASE_USER = "db.user";
  private static final String DATABASE_PASSWORD = "db.password";
  private static final String PACKAGES_TO_SCAN = "packages.to.scan";
  private static final String HIBERNATE_DIALECT = "hibernate.dialect";
  private static final String HIBERNATE_SHOW_SQL = "hibernate.show.sql"; 

  @Resource
  private Environment env; 

  @Bean
  public DataSource dataSource() {
    DruidDataSource source = new DruidDataSource();
    source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
    source.setUrl(env.getRequiredProperty(DATABASE_URL));
    source.setUsername(env.getRequiredProperty(DATABASE_USER));
    source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
    return source;
  } 

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setDataSource(dataSource());
    factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
    factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN));
    factory.setJpaProperties(hibernateProperties());
    factory.afterPropertiesSet();
    return factory;
  } 

  @Bean
  public PlatformTransactionManager transactionManager() {
    JpaTransactionManager manager = new JpaTransactionManager();
    manager.setEntityManagerFactory(entityManagerFactory().getObject());
    return manager;
  } 

  @Bean
  public HibernateExceptionTranslator hibernateExceptionTranslator() {
    return new HibernateExceptionTranslator();
  } 

  private Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put(HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT));
    properties.put(HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL));
    return properties;
  } 

}

但是这一配置是不能简单地扩展到多数据源配置的,因为Spring Boot默认会为开发人员做很多工作,而这些工作与多数据源的配置相冲突,因此需要修改原来的配置内容。网上有很多讲解多数据源配置的文章,但是这些文章大多使用的是XML配置的方式,而且没有使用Spring Boot等比较新的Spring框架技术(比如很多人使用实现AbstractRoutingDataSource这一Spring提供的抽象类的方式,还需要切面的支持,无疑是相当繁琐的),已经不适用于在最新的工程项目中使用了,因为最新的Spring框架可以为我们完成很多事情,我们只需要去适应新的方法即可。为此,我通过研究Spring的官方文档和不断调试,实现了新的多数据源配置的方法,在此贴出,仅供参考。

首先,Spring的JPA是直接支持多数据源配置的,因此我们可以在配置文件或者代码中直接配置多个数据源。由于多数据源配置可能会共享一些配置信息,因此使用继承体系实现这种配置是最合适的。在例子中,我的ORM框架使用的是hibernate,而与Hibernate相关的配置信息我都放在了配置基类BaseJpaConfg中,代码如下。

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class BaseJpaConfig { 

  private static final String HIBERNATE_DIALECT = "hibernate.dialect";
  private static final String HIBERNATE_SHOW_SQL = "hibernate.show.sql"; 

  @Resource
  protected Environment env; 

  @Bean
  public HibernateExceptionTranslator hibernateExceptionTranslator() {
    return new HibernateExceptionTranslator();
  } 

  protected Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put(HIBERNATE_DIALECT, env.getRequiredProperty(HIBERNATE_DIALECT));
    properties.put(HIBERNATE_SHOW_SQL, env.getRequiredProperty(HIBERNATE_SHOW_SQL));
    return properties;
  } 

}

该类提供Hibernate相关信息。它有两个子类,分别是SpringJpaConfig以及MysqlJpaConfig,分别配置了两个数据源,连接到两个不同的数据库Schema,代码如下。

@Configuration
@EnableJpaRepositories(basePackages = {"org.lyndon.repository1"}, entityManagerFactoryRef = "springEntityManagerFactory",
    transactionManagerRef = "springTransactionManager")
public class SpringJpaConfig extends BaseJpaConfig { 

  private static final String DATABASE_DRIVER = "db.driver";
  private static final String DATABASE_URL = "db.url";
  private static final String DATABASE_USER = "db.user";
  private static final String DATABASE_PASSWORD = "db.password";
  private static final String PACKAGES_TO_SCAN = "packages.to.scan"; 

  @Bean
  @ConfigurationProperties(prefix = "datasource.primary")
  public DataSource dataSource() {
    DruidDataSource source = new DruidDataSource();
    source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
    source.setUrl(env.getRequiredProperty(DATABASE_URL));
    source.setUsername(env.getRequiredProperty(DATABASE_USER));
    source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
    return source;
  } 

  @Bean(name = "springEntityManagerFactory")
  public LocalContainerEntityManagerFactoryBean springEntityManagerFactory() {
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setDataSource(dataSource());
    factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
    factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN).split(","));
    factory.setJpaProperties(hibernateProperties());
    factory.afterPropertiesSet();
    return factory;
  } 

  @Bean(name = "springTransactionManager")
  @Primary
  public PlatformTransactionManager transactionManager() {
    JpaTransactionManager manager = new JpaTransactionManager();
    manager.setEntityManagerFactory(springEntityManagerFactory().getObject());
    return manager;
  } 

}
@Configuration
@EnableJpaRepositories(basePackages = {"org.lyndon.repository2"}, entityManagerFactoryRef = "mysqlEntityManagerFactory",
    transactionManagerRef = "mysqlTransactionManager")
public class MysqlJpaConfig extends BaseJpaConfig { 

  private static final String DATABASE_DRIVER = "db.driver";
  private static final String DATABASE_URL = "db.url2";
  private static final String DATABASE_USER = "db.user";
  private static final String DATABASE_PASSWORD = "db.password";
  private static final String PACKAGES_TO_SCAN = "packages.to.scan2"; 

  @Bean
  @ConfigurationProperties(prefix = "datasource.secondary")
  public DataSource dataSource2() {
    DruidDataSource source = new DruidDataSource();
    source.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
    source.setUrl(env.getRequiredProperty(DATABASE_URL));
    source.setUsername(env.getRequiredProperty(DATABASE_USER));
    source.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
    return source;
  } 

  @Bean(name = "mysqlEntityManagerFactory")
  public LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory() {
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setDataSource(dataSource2());
    factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
    factory.setPackagesToScan(env.getRequiredProperty(PACKAGES_TO_SCAN).split(","));
    factory.setJpaProperties(hibernateProperties());
    factory.afterPropertiesSet();
    return factory;
  } 

  @Bean(name = "mysqlTransactionManager")
  public PlatformTransactionManager transactionManager() {
    JpaTransactionManager manager = new JpaTransactionManager();
    manager.setEntityManagerFactory(mysqlEntityManagerFactory().getObject());
    return manager;
  } 

}

两份配置代码使用了各自的数据源、实体管理对象以及事务管理对象。这里要注意的有两点,首先是实体管理对象。Spring Boot框架为方便开发者,默认会寻找名为“entityManagerFactory”的Bean作为实体管理的实现,但是我们这里使用了两个实体管理对象,名称也并不是默认的“entityManagerFactory”,因此必须在各自的EnableJpaRepositories的Annotation中指明使用的实体管理对象。第二点,就是事务管理对象。Spring Boot会提供一个默认的事务管理对象的实现,但是我们在这里使用了两个不同的事务管理对象,因此我们也需要在各自的EnableJpaRepositories的Annotation中指明使用的事务管理对象。除此以外,我们还必须指定其中一个事务管理对象为主要对象(使用Primary这一Annotation),让Spring能有主次地使用相应的事务管理对象。

以上就是本文的主要内容。关于Service的配置等问题,由于和单数据源时是一样的,因此就不再赘述了。基于上述代码,我们就可以使用Spring Boot实现多数据源之间的无缝切换了,是不是很轻松?如果你不想使用代码配置的方式,也可以使用XML文件代替,配置的核心属性与上文相同,可以自己加以琢磨。希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2017-05-16

Spring Boot 集成Mybatis实现主从(多数据源)分离方案示例

本文将介绍使用Spring Boot集成Mybatis并实现主从库分离的实现(同样适用于多数据源).延续之前的Spring Boot 集成MyBatis.项目还将集成分页插件PageHelper.通用Mapper以及Druid. 新建一个Maven项目,最终项目结构如下: 多数据源注入到sqlSessionFactory POM增加如下依赖: <!--JSON--> <dependency> <groupId>com.fasterxml.jackson.core<

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

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

解决spring boot 1.5.4 配置多数据源的问题

spring boot 已经支持多数据源配置了,无需网上好多那些编写什么类的,特别麻烦,看看如下解决方案,官方的,放心! 1.首先定义数据源配置 #=====================multiple database config============================ #ds1 first.datasource.url=jdbc:mysql://localhost/test?characterEncoding=utf8&useSSL=true first.datasou

Spring Boot多数据源及其事务管理配置方法

准备工作 先给我们的项目添加Spring-JDBC依赖和需要访问数据库的驱动依赖. 配置文件 spring.datasource.prod.driverClassName=com.mysql.jdbc.Driver spring.datasource.prod.url=jdbc:mysql://127.0.0.1:3306/prod spring.datasource.prod.username=root spring.datasource.prod.password=123456 spring

springboot + mybatis配置多数据源示例

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

springboot下配置多数据源的方法

一.springboot 简介 SpringBoot使开发独立的,产品级别的基于Spring的应用变得非常简单,你只需"just run". 我们为Spring平台及第三方库提 供开箱即用的设置,这样你就可以有条不紊地开始.多数Spring Boot应用需要很少的Spring配置. 你可以使用SpringBoot创建Java应用,并使用 java -jar 启动它或采用传统的war部署方式.我们也提供了一个运行"spring 脚本"的命令行工具. 二.传统的Dat

使用Spring Boot快速构建基于SQLite数据源的应用

为了提供一个单包易部署的服务器应用,考虑使用Spring Boot,因为其集成了Apache Tomcat,易于运行,免去绝大部分了服务器配置的步骤. 项目初始化 首先从mvn archetype:generate中选择 com.github.mkspcd:simple-webapp(或其他webapp模版) 模版生成项目结构. 更多关于maven请移步Maven - Users Centre 在pom.xml中添加parent来获取Spring Boot所需的最小依赖. <project xm

Spring Boot 快速入门指南

最近因为项目的缘故,需要接触 Spring Boot,详细的介绍可以参考官方的文档,这里主要根据自己学习的实践进行简单分享.版本:1.3.6 简介 Spring 框架是非常著名的 Java 开源框架,历经十多年的发展,整个生态系统已经非常完善甚至是繁杂,Spring Boot 正是为了解决这个问题而开发的,为 Spring 平台和第三方库提供了开箱即用的设置,只需要很少的配置就可以开始一个 Spring 项目.当然,建议使用 Java 8 来进行开发. Spring Boot 实际上走的是 Se

spring boot springjpa 支持多个数据源的实例代码

1.SpringBoot的程序启动类 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.web

Spring Boot 整合mybatis 使用多数据源的实现方法

前言 本篇教程偏向实战,程序猿直接copy代码加入到自己的项目中做简单的修修改改便可使用,而对于springboot以及mybatis不在此进行展开介绍,如有读者希望了解可以给我留言,并持续关注,我后续会慢慢更新.(黑色区域代码部分,安卓手机可手动向左滑动,来查看全部代码) 整合 其实整合很简单,如果是用gradle的话,在build.gradle文件里加入 compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1')

Spring Boot + Mybatis多数据源和动态数据源配置方法

网上的文章基本上都是只有多数据源或只有动态数据源,而最近的项目需要同时使用两种方式,记录一下配置方法供大家参考. 应用场景 项目需要同时连接两个不同的数据库A, B,并且它们都为主从架构,一台写库,多台读库. 多数据源 首先要将spring boot自带的DataSourceAutoConfiguration禁掉,因为它会读取application.properties文件的spring.datasource.*属性并自动配置单数据源.在@SpringBootApplication注解中添加ex

Spring Boot 快速集成 Redis的方法

Spring Boot 如何快速集成 Redis?没错,栈长本文教你,让大家少走弯路! 添加依赖 使用像 Redis 这类的 NoSQL 数据库就必须要依赖 spring-data-redis 这样的能力包,开箱即用,Spring Boot 中都封装好了: 引入spring-boot-starter-data-redis: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>

Spring Boot 快速搭建微服务框架详细教程

前言: SpringBoot是为了简化Spring应用的创建.运行.调试.部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置. 简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题---习惯大于约定. Spring Boot默认使用tomcat作为服务器,使用logback提供日志记录. Spring Boot的主要优点: 为所有Spring开发者更快的入门 开箱即用,提供各种默认配置来简化项目配置 内嵌式容器简化Web项目 没有冗余代码生成和XM

Spring Boot快速入门教程

简介 在您第1次接触和学习Spring框架的时候,是否因为其繁杂的配置而退却了?在你第n次使用Spring框架的时候,是否觉得一堆反复黏贴的配置有一些厌烦?那么您就不妨来试试使用Spring Boot来让你更易上手,更简单快捷地构建Spring应用! Spring Boot让我们的Spring应用变的更轻量化.比如:你可以仅仅依靠一个Java类来运行一个Spring引用.你也可以打包你的应用为jar并通过使用java -jar来运行你的Spring Web应用. Spring Boot的主要优点

Spring Boot Dubbo 构建分布式服务的方法

概述: 节点角色说明 节点 角色说明 Provider 暴露服务的服务提供方 Consumer 调用远程服务的服务消费方 Registry 服务注册与发现的注册中心 Monitor 统计服务的调用次数和调用时间的监控中心 Container 服务运行的容器 调用关系说明 服务容器 Container 负责启动,加载,运行服务提供者. 服务提供者 Provider 启动的时候,向注册中心 Registry 注册自己提供的服务. 服务消费者 Consumer 在启动的时候,向注册中心 Registr

详解SpringBoot 使用Spring Initializr 快速构建工程(官方推荐)

序言: 在此之前,我们主要通过Maven Archetype 来快速生成Maven项目,项目原型相对简陋,对各种IDE的支持也不太友好.然而通过Spring官方提供的Spring Initializr 来构建Maven项目,它不仅完美支持IDEA和Eclipse,而且能自动生成启动类和单元测试代码,给开发人员带来极大的便利!! 注:本文含Eclipse&IDEA两部分教程. 一.Spring Initializr 使用教程 ( Eclipse )具体步骤: 步骤1 : 使用浏览器打开: http