本文是 Spring Boot 整合數據持久化方案的最后一篇,主要和大伙來聊聊 Spring Boot 整合 Jpa 多數據源問題。在 Spring Boot 整合JbdcTemplate 多數據源、Spring Boot 整合 MyBatis 多數據源以及 Spring Boot 整合 Jpa 多數據源這三個知識點中,整合 Jpa 多數據源算是最復雜的一種,也是很多人在配置時最容易出錯的一種。本文大伙就跟着松哥的教程,一步一步整合 Jpa 多數據源。
工程創建
首先是創建一個 Spring Boot 工程,創建時添加基本的 Web、Jpa 以及 MySQL 依賴,如下:
創建完成后,添加 Druid 依賴,這里和前文的要求一樣,要使用專為 Spring Boot 打造的 Druid,大伙可能發現了,如果整合多數據源一定要使用這個依賴,因為這個依賴中才有 DruidDataSourceBuilder,最后還要記得鎖定數據庫依賴的版本,因為可能大部分人用的還是 5.x 的 MySQL 而不是 8.x。完整依賴如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.28</version>
<scope>runtime</scope>
</dependency>
如此之后,工程就創建成功了。
基本配置
在基本配置中,我們首先來配置多數據源基本信息以及 DataSource,首先在 application.properties 中添加如下配置信息:
# 數據源一
spring.datasource.one.username=root
spring.datasource.one.password=root
spring.datasource.one.url=jdbc:mysql:///test01?useUnicode=true&characterEncoding=UTF-8
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
# 數據源二
spring.datasource.two.username=root
spring.datasource.two.password=root
spring.datasource.two.url=jdbc:mysql:///test02?useUnicode=true&characterEncoding=UTF-8
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
# Jpa配置
spring.jpa.properties.database=mysql
spring.jpa.properties.show-sql=true
spring.jpa.properties.database-platform=mysql
spring.jpa.properties.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
這里 Jpa 的配置和上文相比 key 中多了 properties,多數據源的配置和前文一致,然后接下來配置兩個 DataSource,如下:
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.one")
@Primary
DataSource dsOne() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.two")
DataSource dsTwo() {
return DruidDataSourceBuilder.create().build();
}
}
這里的配置和前文的多數據源配置基本一致,但是注意多了一個在 Spring 中使用較少的注解 @Primary,這個注解一定不能少,否則在項目啟動時會出錯,@Primary 表示當某一個類存在多個實例時,優先使用哪個實例。
好了,這樣,DataSource 就有了。
多數據源配置
接下來配置 Jpa 的基本信息,這里兩個數據源,我分別在兩個類中來配置,先來看第一個配置:
@Configuration
@EnableJpaRepositories(basePackages = "org.javaboy.jpa.dao",entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanOne",transactionManagerRef = "platformTransactionManagerOne")
public class JpaConfigOne {
@Autowired
@Qualifier(value = "dsOne")
DataSource dsOne;
@Autowired
JpaProperties jpaProperties;
@Bean
@Primary
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanOne(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsOne)
.packages("org.javaboy.jpa.model")
.properties(jpaProperties.getProperties())
.persistenceUnit("pu1")
.build();
}
@Bean
PlatformTransactionManager platformTransactionManagerOne(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean factoryBeanOne = localContainerEntityManagerFactoryBeanOne(builder);
return new JpaTransactionManager(factoryBeanOne.getObject());
}
}
首先這里注入 dsOne,再注入 JpaProperties,JpaProperties 是系統提供的一個實例,里邊的數據就是我們在 application.properties 中配置的 jpa 相關的配置。然后我們提供兩個 Bean,分別是 LocalContainerEntityManagerFactoryBean 和 PlatformTransactionManager 事務管理器,不同於 MyBatis 和 JdbcTemplate,在 Jpa 中,事務一定要配置。在提供 LocalContainerEntityManagerFactoryBean 的時候,需要指定 packages,這里的 packages 指定的包就是這個數據源對應的實體類所在的位置,另外在這里配置類上通過 @EnableJpaRepositories 注解指定 dao 所在的位置,以及 LocalContainerEntityManagerFactoryBean 和 PlatformTransactionManager 分別對應的引用的名字。
好了,這樣第一個就配置好了,第二個基本和這個類似,主要有幾個不同點:
- dao 的位置不同
- persistenceUnit 不同
- 相關 bean 的名稱不同
注意實體類可以共用。
代碼如下:
@Configuration
@EnableJpaRepositories(basePackages = "org.javaboy.jpa.dao2",entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanTwo",transactionManagerRef = "platformTransactionManagerTwo")
public class JpaConfigTwo {
@Autowired
@Qualifier(value = "dsTwo")
DataSource dsTwo;
@Autowired
JpaProperties jpaProperties;
@Bean
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanTwo(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsTwo)
.packages("org.javaboy.jpa.model")
.properties(jpaProperties.getProperties())
.persistenceUnit("pu2")
.build();
}
@Bean
PlatformTransactionManager platformTransactionManagerTwo(EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean factoryBeanTwo = localContainerEntityManagerFactoryBeanTwo(builder);
return new JpaTransactionManager(factoryBeanTwo.getObject());
}
}
接下來,在對應位置分別提供相關的實體類和 dao 即可,數據源一的 dao 如下:
package org.javaboy.jpa.dao;
public interface UserDao extends JpaRepository<User,Integer> {
List<User> getUserByAddressEqualsAndIdLessThanEqual(String address, Integer id);
@Query(value = "select * from t_user where id=(select max(id) from t_user)",nativeQuery = true)
User maxIdUser();
}
數據源二的 dao 如下:
package org.javaboy.jpa.dao2;
public interface UserDao2 extends JpaRepository<User,Integer> {
List<User> getUserByAddressEqualsAndIdLessThanEqual(String address, Integer id);
@Query(value = "select * from t_user where id=(select max(id) from t_user)",nativeQuery = true)
User maxIdUser();
}
共同的實體類如下:
package org.javaboy.jpa.model;
@Entity(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String address;
//省略getter/setter
}
到此,所有的配置就算完成了,接下來就可以在 Service 中注入不同的 UserDao,不同的 UserDao 操作不同的數據源。
其實整合 Jpa 多數據源也不算難,就是有幾個細節問題,這些細節問題解決,其實前面介紹的其他多數據源整個都差不多。
好了,本文就先介紹到這里。
相關案例已經上傳到 GitHub,歡迎小伙伴們們下載:https://github.com/lenve/javaboy-code-samples