1. 程式人生 > >Spring Boot Jpa多資料來源配置

Spring Boot Jpa多資料來源配置

前言
隨著業務量發展,我們通常會進行資料庫拆分或是引入其他資料庫,從而我們需要配置多個數據源,如:user一個庫,business一個庫。那麼接下來我們就要考慮怎麼去在spring boot中實現多個數據源的配置。

×××

實現
建表
首先是建表語句,我們要建立兩個資料庫,並各庫內新建一張表
user表
mysql> use user
mysql> select * from user;
+----+-------+----------+
| id | name | password |
+----+-------+----------+
| 1 | 使用者A | ** |
+----+-------+----------+
1 row in set
business表
mysql> use business


mysql> select * from business;
+----+-------+-------------+
| id | name | description |
+----+-------+-------------+
| 1 | 業務A | 業務A描述 |
+----+-------+-------------+
1 row in setbr/>接下來我們通過程式碼實現對兩個庫內的多張表進行查詢。
配置
首先,建立一個Spring配置類,定義兩個DataSource用來讀取application.yml中的不同配置。本文中,我們user做為主資料來源,主資料來源配置為spring.datasource.user開頭的配置,business資料來源配置為spring.datasource.business開頭的配置。
@Configuration
public class DataSourceConfig {
br/>@Primary
@Bean(name = "userDataSource")
br/>@Qualifier("userDataSource")
@ConfigurationProperties(prefix = "spring.datasource.user")
public DataSource userDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "businessDataSource")
br/>@Qualifier("businessDataSource")
@ConfigurationProperties(prefix = "spring.datasource.business")
public DataSource businessDataSource() {
return DataSourceBuilder.create().build();
}
}
對應的配置檔案application.yml如下:
spring:
datasource:
user:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/user
username: root
password: 123456
business:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/business
username: root
password: 123456
br/>接下來我們對各資料來源進行jpa的配置
主資料來源User
@Configuration
@EnableTransactionManagement
br/>@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryUser",
transactionManagerRef = "transactionManagerUser",
//設定Repository所在位置
basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.user"})
public class UserConfig {
br/>@Autowired
@Qualifier("userDataSource")
private DataSource userDataSource;
br/>@Autowired
private JpaProperties jpaProperties;
br/>@Autowired
private HibernateProperties hibernateProperties;
br/>@Primary
@Bean(name = "entityManagerUser")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryUser(builder).getObject().createEntityManager();
br/>}
@Primary
@Bean(name = "entityManagerFactoryUser")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryUser(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(userDataSource)
//設定entity所在位置
.packages("com.ppc.spring.example.jpamultidatasource.entity.user")
.persistenceUnit("userPersistenceUnit")
.properties(getVendorProperties())
.build();
}
private Map<String, Object> getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
br/>}
@Primary
@Bean(name = "transactionManagerUser")
public PlatformTransactionManager transactionManagerUser(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryUser(builder).getObject());
br/>}
}
其他資料來源business
@Configuration
@EnableTransactionManagement
br/>@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryBusiness",
transactionManagerRef = "transactionManagerBusiness",
//設定repository所在位置
basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.business"})
public class BusinessConfig {
br/>@Autowired
@Qualifier("businessDataSource")
private DataSource businessDataSource;
br/>@Autowired
private JpaProperties jpaProperties;
br/>@Autowired
private HibernateProperties hibernateProperties;
@Bean(name = "entityManagerBusiness")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryBusiness(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactoryBusiness")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBusiness(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(businessDataSource)
.properties(getVendorProperties())
//設定實體類所在位置
.packages("com.ppc.spring.example.jpamultidatasource.entity.business")
.persistenceUnit("businessPersistenceUnit")
.build();
}
private Map<String, Object> getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
@Bean(name = "transactionManagerBusiness")
PlatformTransactionManager transactionManagerBusiness(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryBusiness(builder).getObject());
}
}
配置中需要注意以下幾點:
Spring Boot 1.5.x
private Map<String, String> getVendorProperties() {
return jpaProperties.getHibernateProperties(userDataSource);
}
Spring Boot 2.0.x
private Map<String, Object> getVendorProperties() {
return jpaProperties.getHibernateProperties(new HibernateSettings());
}
Spring Boot 2.1.0參見上文程式碼,引進了HibernateProperties。同時,在Spring Boot 2.1.0中預設的mysql-connector-java版本為8.0.13,連線低版本mysql配置上比較繁瑣,建議在配置檔案中手動指定相應版本,如本文中指定5.1.46這個版本。
runtimeOnly('mysql:mysql-connector-java:5.1.46')
repository、entity的所在位置,要和實際儲存的位置一致。

主資料來源的一些配置需要新增@Primary作為spring預設的首選項,其他資料來源無需新增該註解。

通過檢視相關原始碼我們看到Spring Boot中JpaProperties的程式碼一直在調整,這裡我們將properties相關程式碼單獨提取出作為一個單獨的方法getVendorProperties展示版本間的區別。其中:br/>查詢
完成了所有的配置,接下來我們就可以開始寫個簡單程式碼驗證我們配置了
@RestController
@SpringBootApplication
public class JpaMultiDatasourceApplication {
br/>@Autowired
UserRepository userRepository;
br/>@Autowired
Busine***epository busine***epository;
public static void main(String[] args) {
SpringApplication.run(JpaMultiDatasourceApplication.class, args);
br/>}
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return userRepository.findById(id).orElse(null);
br/>}
@GetMapping("/business/{id}")
public Business getBusiness(@PathVariable Long id) {
return busine***epository.findById(id).orElse(null);
}
}
我們對外暴露了兩個介面,分別訪問user表、business表確認可以正常獲取資料。查詢結果如下:
請求:
http://localhost:8080/user/1
結果:{"id":1,"name":"使用者A","password":"**"}
請求:http://localhost:8080/business/1
結果:{"id":1,"name":"業務A","description":"業務A描述"}
就此,我們雙資料來源的配置和驗證工作就完成了。