Springboot 之 JPA 多数据源实现
简介
微服务推崇单服务单数据库;但是还是免不了存在一个微服务连接多个数据库的情况,今天介绍一下如何使用 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);
}
}