場景 : 配置兩個數據源,主數據源是mysql , 次數據源是impala [1] , 兩個個數據源都使用spring-data-jpa 。
一、環境
- 基礎組件版本
maven: 3.5.3
spring-boot: 2.0.1
spring-data: 2.0.5
jdk: 8
- 先把項目結構分成三部分,方便理解, 我們要做的就是用不同的持久層使用不同的數據源
src
├─持久層
│ ├─domain
│ └─repository
│
├─服務層
│ └─service
│
└─控制層
└─controller
- 如果使用多數據源,結構主要結構看起來如下,
服務層
和控制層
不變
src
├─mysql持久層
│ ├─domain
│ └─repository
│
├─impala持久層
│ ├─domain
│ └─repository
│
├─服務層
│ └─service
│
└─控制層
└─controller
二、配置多數據源
- 增加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
- 分隔持久層,就是建兩個不同的包,持久層分開放。
-
defaultDataSource
存放的是mysql的實體類和DAO ,impalaDataSource
放impala的DAO和實體類
image.png
- 配置datasource
- 新建
DefaultDBConfig
類,配置mysql的dataSource
、entityManagerFactory
和transactionManager
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);
}
}
- 要注意的地方和上面 mysql的一樣。【2】標注的
impala.datasource
是自定義的前綴,可以自己定義,這里寫成對應的就可以獲取到配置 .- 配置完上面的就ok了,在spring-boot中,controller和service層都不用做什么修改(我的項目中全部用的 JPA)
可能會出現的問題
- 實體類中命名解析無效,比如實體類中的 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
-
Impala是Cloudera公司主導開發的新型查詢系統,它提供SQL語義,能查詢存儲在Hadoop的HDFS和HBase中的PB級大數據 ?