简介
微服务推崇单服务单数据库;但是还是免不了存在一个微服务连接多个数据库的情况,今天介绍一下如何使用 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 /> |
| </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 配置
| |
| |
| |
| @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数据源
| |
| |
| |
| |
| |
| @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") |
| 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 数据源源
| |
| |
| |
| @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") |
| 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") |
| 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") |
| 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); |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· Qt个人项目总结 —— MySQL数据库查询与断言