spring boot 2 多数据源详细配置

场景 : 配置两个数据源,主数据源是mysql , 次数据源是impala [1] , 两个个数据源都使用spring-data-jpa 。

一、环境

  1. 基础组件版本
maven: 3.5.3
spring-boot: 2.0.1
spring-data: 2.0.5
jdk: 8
  1. 先把项目结构分成三部分,方便理解, 我们要做的就是用不同的持久层使用不同的数据源
src
├─持久层
│  ├─domain
│  └─repository
│  
├─服务层
│  └─service
│
└─控制层
    └─controller
  1. 如果使用多数据源,结构主要结构看起来如下,服务层控制层不变
src
├─mysql持久层
│  ├─domain
│  └─repository
│  
├─impala持久层
│  ├─domain
│  └─repository
│  
├─服务层
│  └─service
│
└─控制层
    └─controller

二、配置多数据源

  1. 增加yaml配置
  • mysql配置
spring:
    datasource:
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://100.100.100:3306/db_mysql?useUnicode=true&characterEncoding=utf-8&useSSL=false&zeroDateTimeBehavior=convertToNull&useNewIO=true&autoReconnectForPools=true
        username: user
        password: pwd
  • impala配置 (impala:是自定义的,这个结构可以全部自定义)
impala:
    datasource:
        url: jdbc:hive2://finance-06:21050/db_impala;auth=noSasl;
        username: user
        password: pwd
  1. 分隔持久层,就是建两个不同的包,持久层分开放。
  • defaultDataSource存放的是mysql的实体类和DAO , impalaDataSource放impala的DAO和实体类
    image.png
  1. 配置datasource
  • 新建DefaultDBConfig类,配置mysql的dataSourceentityManagerFactorytransactionManager
package com.demo.conf;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactory", 
        transactionManagerRef = "transactionManager", 
        // 【1】这里写的是DAO层的路径 ,如果你的DAO放在 com.xx.DAO下面,则这里写成 com.xx.DAO
        basePackages = {"com.demo.defaultDataSource.repository"}  
)
public class DefaultDBConfig {

    @Autowired
    private JpaProperties jpaProperties;

    @Primary
    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource") // 【2】datasource配置的前缀,对应上面 【mysql的yaml配置】
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "entityManagerFactory") 
    public LocalContainerEntityManagerFactoryBean
    entityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("dataSource") DataSource dataSource
    ) {
        return builder
                .dataSource(dataSource)
                .packages("com.demo.defaultDataSource.domain") // 【3】这里是实体类的包路径
                .persistenceUnit("defaultUnit") // 这里写成唯一的就可以了,具体我也不太明白 ,希望有人告知
                  // 【4】
                .properties(jpaProperties.getHibernateProperties(new HibernateSettings())) 
                .build();
    }

    @Primary
    @Bean(name = "transactionManager") 
    public PlatformTransactionManager transactionManager(
            @Qualifier("entityManagerFactory") EntityManagerFactory
                    entityManagerFactory
    ) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

注意上面标的【1】【2】【3】【4】这四个地方,
【1】:设置DAO所在的包路径
【2】:datasource的yaml配置前缀,默认数据原最好保持为spring.datasource
【3】:这里是实体类的包路径,里面是 @Entity 注解的实体,对应数据库的表。
【4】:因为这里自己生成数据源,没有spring-boot的自动配置了,所以要通过 JpaProperties 获取默认配置并放进去,这里算是小重点
注意:这里配置的为默认数据源,记得加上@Primary

  • image.png

    注意 : 图片中相同颜色和数字标注的地方要保持统一

图片是以前的老图,没有加@Primary,在实际代码中记得加上


  • 新建ImpalaDBConfig类,配置impala的dataSource、entityManagerFactory和transactionManager
package com.bbd.finance.xuanwu.web.conf;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "impalaEntityManagerFactory" ,
        transactionManagerRef = "impalaTransactionManager" ,
        basePackages = {"com.demo.impalaDataSource.dao"} // 【1】
)
public class ImpalaDBConfig {
    @Autowired
    private JpaProperties jpaProperties ;
    
   
    @Bean(name = "impalaDataSource")
    @ConfigurationProperties(prefix = "impala.datasource") // 【2】
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
    

    @Bean(name = "impalaEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean
    entityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("impalaDataSource") DataSource dataSource , Environment environment
    ) {
        
        LocalContainerEntityManagerFactoryBean impala = builder
                .dataSource(dataSource)
                .packages("com.demo.impalaDataSource.domain") // 【3】
                .persistenceUnit("impala")
                // 【4】
                .properties(jpaProperties.getHibernateProperties(new HibernateSettings())) 
                .build();
        return impala ;
    }
    

    @Bean(name = "impalaTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("impalaEntityManagerFactory") EntityManagerFactory
                    entityManagerFactory
    ) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}
  1. 要注意的地方和上面 mysql的一样。【2】标注的impala.datasource是自定义的前缀,可以自己定义,这里写成对应的就可以获取到配置 .
  2. 配置完上面的就ok了,在spring-boot中,controller和service层都不用做什么修改(我的项目中全部用的 JPA)

可能会出现的问题
  1. 实体类中命名解析无效,比如实体类中的 userName , 没有自动映射成数据中的 user_name , 因为自己构建的数据源没有加载到 命名策略 , 此时请检查上面代码标注的第【4】点 , 可以在【4】标注的地方断点,看有没有加载 org.hibernate.boot.model.naming.SpringPhysicalNamingStrategy
    image.png
1. 如果要实现mysql和oracle的多数据源,配置方法类似,把impala的配置改成oracle的就ok
2. 多数据源中默认数据源要加上@Primary , (entityManagerFactory , transactionManager ,dataSource )

2018-11-30 更新 : 图片部分就不做更新了哈

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource") // 【2】datasource配置的前缀,对应上面 【mysql的yaml配置】
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

请把▲上面部分的代码换成▼下面的,这样可以解决报错 jdbcUrl is required with driverClassName。原因是spring-boot 1.x 数据源使用的是spring.datasource.url , 而spring-boot 2.x 使用的是spring.datasource.jdbcUrl , 代码修改成下面的样子,可以自动兼容 。官方文档- 79.2 Configure Two DataSources

    @Bean(name = "dataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(@Autowired @Qualifier("defaultDataSourceProperties") DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }

    @Bean(name="defaultDataSourceProperties")
    @ConfigurationProperties("spring.datasource")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

参考:

  • spring data jpa NamingStrategy
  • Can't set JPA naming strategy after configuring multiple data sources (Spring 1.4.1 / Hibernate 5.x)
  • Spring Boot多数据源配置与使用
  • Using multiple datasources with Spring Boot and Spring Data ⇄ ⇄ [要翻墙]
  • Using Multiple DataSources with Spring Boot and JPA
  • Spring Boot Multiple Database Configuration Example
  • Use Two EntityManagers

  1. Impala是Cloudera公司主导开发的新型查询系统,它提供SQL语义,能查询存储在Hadoop的HDFS和HBase中的PB级大数据 ↩

你可能感兴趣的:(spring boot 2 多数据源详细配置)