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