前言
隨著業(yè)務量發(fā)展,我們通常會進行數(shù)據(jù)庫拆分或是引入其他數(shù)據(jù)庫,從而我們需要配置多個數(shù)據(jù)源,如:user一個庫,business一個庫。那么接下來我們就要考慮怎么去在spring boot中實現(xiàn)多個數(shù)據(jù)源的配置。
源碼下載
實現(xiàn)
建表
首先是建表語句,我們要建立兩個數(shù)據(jù)庫,并各庫內(nèi)新建一張表
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 | 業(yè)務A | 業(yè)務A描述 ? |
+----+-------+-------------+
1 row in set
接下來我們通過代碼實現(xiàn)對兩個庫內(nèi)的多張表進行查詢。
配置
首先,創(chuàng)建一個Spring配置類,定義兩個DataSource用來讀取application.yml中的不同配置。本文中,我們user做為主數(shù)據(jù)源,主數(shù)據(jù)源配置為spring.datasource.user開頭的配置,business數(shù)據(jù)源配置為spring.datasource.business開頭的配置。
@Configuration
public class DataSourceConfig {
? ?@Primary
? ?@Bean(name = "userDataSource")
? ?@Qualifier("userDataSource")
? ?@ConfigurationProperties(prefix = "spring.datasource.user")
? ?public DataSource userDataSource() {
? ? ? ?return DataSourceBuilder.create().build();
? ?}
? ?@Bean(name = "businessDataSource")
? ?@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
接下來我們對各數(shù)據(jù)源進行jpa的配置
主數(shù)據(jù)源User
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
? ? ? ?entityManagerFactoryRef = "entityManagerFactoryUser",
? ? ? ?transactionManagerRef = "transactionManagerUser",
? ? ? ?//設置Repository所在位置
? ? ? ?basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.user"})
public class UserConfig {
? ?@Autowired
? ?@Qualifier("userDataSource")
? ?private DataSource userDataSource;
? ?@Autowired
? ?private JpaProperties jpaProperties;
? ?@Autowired
? ?private HibernateProperties hibernateProperties;
? ?@Primary
? ?@Bean(name = "entityManagerUser")
? ?public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
? ? ? ?return entityManagerFactoryUser(builder).getObject().createEntityManager();
? ?}
? ?@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());
? ?}
? ?@Primary
? ?@Bean(name = "transactionManagerUser")
? ?public PlatformTransactionManager transactionManagerUser(EntityManagerFactoryBuilder builder) {
? ? ? ?return new JpaTransactionManager(entityManagerFactoryUser(builder).getObject());
? ?}
}
其他數(shù)據(jù)源business
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
? ? ? ?entityManagerFactoryRef = "entityManagerFactoryBusiness",
? ? ? ?transactionManagerRef = "transactionManagerBusiness",
? ? ? ?//設置repository所在位置
? ? ? ?basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.business"})
public class BusinessConfig {
? ?@Autowired
? ?@Qualifier("businessDataSource")
? ?private DataSource businessDataSource;
? ?@Autowired
? ?private JpaProperties jpaProperties;
? ?@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的所在位置,要和實際保存的位置一致。
主數(shù)據(jù)源的一些配置需要添加@Primary作為spring默認的首選項,其他數(shù)據(jù)源無需添加該注解。
通過查看相關源碼我們看到Spring Boot中JpaProperties的代碼一直在調(diào)整,這里我們將properties相關代碼單獨提取出作為一個單獨的方法getVendorProperties展示版本間的區(qū)別。其中:
查詢
完成了所有的配置,接下來我們就可以開始寫個簡單代碼驗證我們配置了
@RestController
@SpringBootApplication
public class JpaMultiDatasourceApplication {
? ?@Autowired
? ?UserRepository userRepository;
? ?@Autowired
? ?BusinessRepository businessRepository;
? ?public static void main(String[] args) {
? ? ? ?SpringApplication.run(JpaMultiDatasourceApplication.class, args);
? ?}
? ?@GetMapping("/user/{id}")
? ?public User getUser(@PathVariable Long id) {
? ? ? ?return userRepository.findById(id).orElse(null);
? ?}
? ?@GetMapping("/business/{id}")
? ?public Business getBusiness(@PathVariable Long id) {
? ? ? ?return businessRepository.findById(id).orElse(null);
? ?}
}
我們對外暴露了兩個接口,分別訪問user表、business表確認可以正常獲取數(shù)據(jù)。查詢結果如下:
請求:http://localhost:8080/user/1
結果:{"id":1,"name":"用戶A","password":"******"}
請求:http://localhost:8080/business/1
結果:{"id":1,"name":"業(yè)務A","description":"業(yè)務A描述"}
就此,我們雙數(shù)據(jù)源的配置和驗證工作就完成了。