簡介
微服務推崇單服務單資料庫;但是還是免不了存在一個微服務連接配接多個資料庫的情況,今天介紹一下如何使用 JPA 的多資料源。主要采用将不同資料庫的 Repository 接口分别存放到不同的 package,Spring 去掃描不同的包,注入不同的資料源來實作多資料源。
建立 jpa-multip-datasource 項目
分别建立db01和db02資料庫
學生表 t_student
CREATE TABLE `t_student` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`sex` int(1) NULL DEFAULT NULL ,
`grade` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=1 ROW_FORMAT=DYNAMIC;
教師表 t_teacher
CREATE TABLE `t_teacher` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`sex` int(1) NULL DEFAULT NULL ,
`office` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=1 ROW_FORMAT=DYNAMIC;
pom.xml檔案引入如下依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.olive</groupId>
<artifactId>jpa-multip-datasource</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jpa-multip-datasource</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.14</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
配置兩個資料源
分别為第一個主資料源(primary),第二資料源(second),具體配置如下:
# 基本配置
server:
port: 8080
# 資料庫
spring:
jpa:
show-sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
hibernate:
ddl-auto: update
datasource:
primary:
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/db01?characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true
username: root
password: root
sencond:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/db02?characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true
username: root
password: root
jackson:
serialization:
indent-output: true
配置資料源
DataSourceConfig 配置
/**
* @Description: 資料源配置
*/
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
@Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondDataSource")
@Qualifier("secondDataSource")
@ConfigurationProperties(prefix = "spring.datasource.sencond")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
}
PrimaryConfig資料源
/**
* @Description: 主資料源配置
* @date
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com.olive.repository.primary"})
public class PrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Autowired
private HibernateProperties hibernateProperties;
@Autowired
private JpaProperties jpaProperties;
@Primary
@Bean(name = "entityManagerPrimary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}
@Primary
@Bean(name = "entityManagerFactoryPrimary") //primary實體工廠
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
return builder.dataSource(primaryDataSource)
.properties(getHibernateProperties())
.packages("com.olive.entity.primary") //換成你自己的實體類所在位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}
@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
private Map<String, Object> getHibernateProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
}
SecondConfig 資料源源
/**
* @Description: 第二個資料源配置
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactorySecond",
transactionManagerRef = "transactionManagerSecond",
basePackages = {"com.olive.repository.second"})
public class SecondConfig {
@Autowired
@Qualifier("secondDataSource")
private DataSource secondDataSource;
@Resource
private JpaProperties jpaProperties;
@Resource
private HibernateProperties hibernateProperties;
@Bean(name = "entityManagerSecond")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySecond(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactorySecond") //primary實體工廠
public LocalContainerEntityManagerFactoryBean entityManagerFactorySecond (EntityManagerFactoryBuilder builder) {
return builder.dataSource(secondDataSource)
.properties(getHibernateProperties())
.packages("com.olive.entity.second") //換成你自己的實體類所在位置
.persistenceUnit("secondaryPersistenceUnit")
.build();
}
@Bean(name = "transactionManagerSecond")
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySecond(builder).getObject());
}
private Map<String, Object> getHibernateProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
}
建立學生與老師實體類
Student實體類
package com.olive.entity.primary;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Data;
@Data
@Entity(name="t_student")
public class StudentDO implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_name") // 若實體屬性和表字段名稱一緻時,可以不用加@Column注解
private String name;
@Column(name = "sex")
private int sex;
@Column(name = "grade")
private String grade;
}
Teacher實體類
package com.olive.entity.second;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Data;
@Data
@Entity(name="t_teacher")
public class TeacherDO implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_name") // 若實體屬性和表字段名稱一緻時,可以不用加@Column注解
private String name;
@Column(name = "sex")
private int sex;
@Column(name = "office")
private String office;
}
資料庫持久類
StudentRepository類
package com.olive.repository.primary;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.olive.entity.primary.StudentDO;
@Repository
public interface StudentRepository extends JpaRepository<StudentDO, Long> {
}
TeacherRepository類
package com.olive.repository.second;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.olive.entity.second.TeacherDO;
@Repository
public interface TeacherRepository extends JpaRepository<TeacherDO, Long> {
}
建立springboot引導類
package com.olive;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
測試
package com.olive;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.olive.entity.primary.StudentDO;
import com.olive.entity.second.TeacherDO;
import com.olive.repository.primary.StudentRepository;
import com.olive.repository.second.TeacherRepository;
@SpringBootTest
public class JpaTest {
@Autowired
StudentRepository studentRepository;
@Autowired
TeacherRepository teacherRepository;
@Test
public void userSave() {
StudentDO studentDO = new StudentDO();
studentDO.setName("BUG弄潮兒");
studentDO.setSex(1);
studentDO.setGrade("一年級");
studentRepository.save(studentDO);
TeacherDO teacherDO = new TeacherDO();
teacherDO.setName("Java樂園");
teacherDO.setSex(2);
teacherDO.setOffice("國文");
teacherRepository.save(teacherDO);
}
}