详解基于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文件代替,配置的核心属性与上文相同,可以自己加以琢磨。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

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

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

  • 使用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 集成Mybatis实现主从(多数据源)分离方案示例

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

  • 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

  • 解决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

  • 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与Spring Data JPA的多数据源配置

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

  • 详解基于iview-ui的导航栏路径(面包屑)配置

    起因 上家公司的后台管理系统都是刷表刷出来的,所用很久很久没写后台管理系统了.换了工作后总算要开始捣腾router了,很久没用都快忘光了,所以把一些通用的模块记录一下,也分享给需要的朋友们. 经过 //router.js let routes = [ { path: '/', redirect: '/admin', }, { path: '/login', name: 'login', meta: {title: '登录'}, component: () => import('./compone

  • 详解基于Spring Data的领域事件发布

    领域事件发布是一个领域对象为了让其它对象知道自己已经处理完成某个操作时发出的一个通知,事件发布力求从代码层面让自身对象与外部对象解耦,并减少技术代码入侵. 一. 手动发布事件 // 实体定义 @Entity public class Department implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer departmentId; @Enumerate

  • Spring Boot整合Spring Data JPA过程解析

    Spring Boot整合Spring Data JPA 1)加入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> &l

  • 详解基于JWT的springboot权限验证技术实现

    JWT简介 Json Web Token(JWT):JSON网络令牌,是为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准((RFC 7519).JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式用于通信双方之间以 JSON 对象行使安全的传递信息.因为数字签名的存在,这些信息是可信的. 实现步骤: 环境spring boot 1.添加jwt依赖 <dependency> <groupId>com.auth0</groupId> <ar

  • spring boot与spring mvc的区别及功能介绍

    Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等.但他们的基础都是Spring 的 ioc和 aop ioc 提供了依赖注入的容器 aop ,解决了面向横切面的编程,然后在此两者的基础上实现了其他延伸产品的高级功能.Spring MVC是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题,因为 Spring 的配置非常复杂,各种XML. JavaConfig.hin处理起来比较繁琐.于是为了简化开发者的使用,从而创造性地推出了Spr

  • Spring Boot整合Spring Security简单实现登入登出从零搭建教程

    前言 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. 本文主要给大家介绍了关于Spring Boot整合S

  • Spring Boot整合Spring Cache及Redis过程解析

    这篇文章主要介绍了Spring Boot整合Spring Cache及Redis过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.安装redis a.由于官方是没有Windows版的,所以我们需要下载微软开发的redis,网址: https://github.com/MicrosoftArchive/redis/releases b.解压后,在redis根目录打开cmd界面,输入:redis-server.exe redis.wind

  • JAVA入门教学之快速搭建基本的springboot(从spring boot到spring cloud)

    安装JDK https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html 使用的是jdk8,这里使用的是windows10 64位的操作系统,所以下载对应的jdk版本 点击链接会要你登录,登录以后才可以下载. 下载安装以后找到jdk的安装目录,我这里是C:\Program Files\Java\jdk1.8.0_211 配置JAVA_HOME,值就是你安装jdk的地址C:\Program Files\Java

  • 详解基于MybatisPlus两步实现多租户方案

    1.定义一个TenantLineHandler的实现类: import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.google.common.collect.Lists; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; import ja

随机推荐