Spring Boot 整合 JPA 使用多個數據源
阿新 • • 發佈:2019-08-08
介紹
JPA(Java Persistence API)Java 持久化 API,是 Java 持久化的標準規範,Hibernate 是持久化規範的技術實現,而 Spring Data JPA 是在 Hibernate 基礎上封裝的一款框架。
第一次使用 Spring JPA 的時候,感覺這東西簡直就是神器,幾乎不需要寫什麼關於資料庫訪問的程式碼一個基本的 CURD 的功能就出來了。在這篇文章中,我們將介紹 Spring Boot 整合 JPA 使用多個數據源的方法。
開發環境:
- Spring Boot 2.0.5
- Spring Data JPA 2.0.5
- MySQL 5.6
- JDK 8
- IDEA 2018.3
- Windows 10
引入依賴
首先我們要 Spring Boot 引入 spring-boot-starter-data-jpa
依賴。
Maven 配置:
<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>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
Gradle 配置:
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.0.5.RELEASE' compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.5.RELEASE' compile group: 'org.springframework.boot', name: 'spring-boot-devtools', version: '2.0.5.RELEASE' compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
配置資料來源
Spring Boot 提供了使用 application.properties 或 application.yml 檔案配置專案屬性的方法。我比較習慣使用 application.yml 檔案,所以這裡我只列出 application.yml 檔案的寫法。
spring:
datasource:
product:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/product?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
username: root
password: test123$
customer:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/customer?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
username: root
password: test123$
jpa:
generate-ddl: true
配置好 application.yml 檔案後分別在資料庫建立 customer 和 product 資料庫。
新增實體(Entity)類
客戶實體:
package com.springboot.jpa.customer.models;
import javax.persistence.*;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true, nullable = false)
private String email;
private String firstName;
private String lastName;
protected Customer() {
}
public Customer(String email, String firstName, String lastName) {
this.email = email;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("Customer[id=%d, firstName='%s', lastName='%s',email='%s']", id, firstName, lastName, email);
}
public Integer getId() {
return id;
}
public String getEmail() {
return email;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
產品實體:
package com.springboot.jpa.product.models;
import javax.persistence.*;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false)
private String code;
private String name;
private double price;
protected Product() {
}
public Product(String code, String name, double price) {
this.code = code;
this.name = name;
this.price = price;
}
@Override
public String toString() {
return String.format("Product[id=%d, code='%s', name='%s', price='%s']", id, code, name, price);
}
public int getId() {
return id;
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
新增資料倉庫(Repository)類
客戶 Repository:
package com.springboot.jpa.customer.repository;
import com.springboot.jpa.customer.models.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
}
產品 Repository:
package com.springboot.jpa.product.repository;
import com.springboot.jpa.product.models.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
新增配置(Config)類
客戶配置:
package com.springboot.jpa.customer.config;
import org.springframework.beans.factory.annotation.Qualifier;
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.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;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "customerEntityManagerFactory", transactionManagerRef = "customerTransactionManager", basePackages = {"com.springboot.jpa.customer.repository"})
public class CustomerConfig {
@Primary
@Bean(name = "customerDataSource")
@ConfigurationProperties(prefix = "spring.datasource.customer")
public DataSource customerDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "customerEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("customerDataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.springboot.jpa.customer.data").persistenceUnit("customer").build();
}
@Primary
@Bean(name = "customerTransactionManager")
public PlatformTransactionManager customerTransactionManager(@Qualifier("customerEntityManagerFactory") EntityManagerFactory customerEntityManagerFactory) {
return new JpaTransactionManager(customerEntityManagerFactory);
}
}
產品配置:
package com.springboot.jpa.product.config;
import org.springframework.beans.factory.annotation.Qualifier;
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;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "productEntityManagerFactory", transactionManagerRef = "productTransactionManager", basePackages = {"com.springboot.jpa.product.repository"}
)
public class ProductConfig {
@Bean(name = "productDataSource")
@ConfigurationProperties(prefix = "spring.datasource.product")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "productEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("productDataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.springboot.jpa.product.data").persistenceUnit("product").build();
}
@Bean(name = "productTransactionManager")
public PlatformTransactionManager productTransactionManager(@Qualifier("productEntityManagerFactory") EntityManagerFactory productEntityManagerFactory) {
return new JpaTransactionManager(productEntityManagerFactory);
}
}
專案結構:
src/main/java
- com.springboot.jpa
- product
- config
- models
- repository
- customer
- config
- models
- repository
新增測試類
客戶測試類 CustomerDataSourcesTests:
package com.springboot.jpa;
import com.springboot.jpa.customer.repository.CustomerRepository;
import com.springboot.jpa.customer.models.Customer;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomerDataSourcesTests {
@Autowired
private CustomerRepository customerRepository;
@Test
@Transactional("customerTransactionManager")
public void createCustomer() {
Customer customer = new Customer("[email protected]", "Charles", "Zhang");
customer = customerRepository.save(customer);
assertNotNull(customerRepository.findById(customer.getId()));
assertEquals(customerRepository.findById(customer.getId()).get().getEmail(), "[email protected]");
}
}
產品測試類 ProductDataSourcesTests:
package com.springboot.jpa;
import com.springboot.jpa.product.models.Product;
import com.springboot.jpa.product.repository.ProductRepository;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductDataSourcesTests {
@Autowired
private ProductRepository productRepository;
@Test
@Transactional("productTransactionManager")
public void createProduct() {
Product product = new Product("10000", "Book", 80.0);
product = productRepository.save(product);
assertNotNull(productRepository.findById(product.getId()));
}
}
測試
分別執行兩個測試類通過後,查詢資料庫。
客戶表:
mysql> SELECT * FROM customer;
+----+-------------------+-----------+----------+
| id | email | firstName | lastName |
+----+-------------------+-----------+----------+
| 1 | [email protected] | Charles | Zhang |
+----+-------------------+-----------+----------+
1 row in set
產品表:
mysql> SELECT * FROM product;
+----+-------+------+-------+
| id | code | name | price |
+----+-------+------+-------+
| 1 | 10000 | Book | 80 |
+----+-------+------+-------+
1 row in set
本文地址:Spring Boot 整合 JPA 使用多個數據源
專案地址:spring-boot-