Spring Boot 整合 JPA 使用多個數據源

介紹

JPA(Java Persistence API)Java 持久化 API,是 Java 持久化的標準規範,Hibernate 是持久化規範的技術實現,而 Spring Data JPA 是在 Hibernate 基礎上封裝的一款框架。
第一次使用 Spring JPA 的時候,感受這東西簡直就是神器,幾乎不須要寫什麼關於數據庫訪問的代碼一個基本的 CURD 的功能就出來了。在這篇文章中,咱們將介紹 Spring Boot 整合 JPA 使用多個數據源的方法。
開發環境:java

  • 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 依賴。mysql

Maven 配置:git

<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 配置:github

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 文件的寫法。web

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 數據庫。spring

添加實體(Entity)類

客戶實體:sql

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:springboot

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:bash

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.models").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.models").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("master@weilog.net", "Charles", "Zhang");
        customer = customerRepository.save(customer);
        assertNotNull(customerRepository.findById(customer.getId()));
        assertEquals(customerRepository.findById(customer.getId()).get().getEmail(), "master@weilog.net");
    }
}

產品測試類 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 | master@weilog.net | 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-jpa

相關文章
相關標籤/搜索