From ff28784dcac06de168fb2e57ea44807709224383 Mon Sep 17 00:00:00 2001
From: "Yangkai.Shen" <237497819@qq.com>
Date: Fri, 18 Jan 2019 16:18:39 +0800
Subject: [PATCH] =?UTF-8?q?:sparkles:=20spring-boot-demo-multi-datasource-?=
=?UTF-8?q?jpa=20=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../README.md | 556 ++++++++++++++++++
spring-boot-demo-multi-datasource-jpa/pom.xml | 2 +-
.../jpa/config/SecondDataSourceConfig.java | 1 -
3 files changed, 557 insertions(+), 2 deletions(-)
create mode 100644 spring-boot-demo-multi-datasource-jpa/README.md
diff --git a/spring-boot-demo-multi-datasource-jpa/README.md b/spring-boot-demo-multi-datasource-jpa/README.md
new file mode 100644
index 0000000..7f432a9
--- /dev/null
+++ b/spring-boot-demo-multi-datasource-jpa/README.md
@@ -0,0 +1,556 @@
+# spring-boot-demo-multi-datasource-jpa
+
+> 此 demo 主要演示 Spring Boot 如何集成 JPA 的多数据源。
+
+## pom.xml
+
+```xml
+
+
+ * JPA多数据源配置 - 主数据源 + *
+ * + * @package: com.xkcoding.multi.datasource.jpa.config + * @description: JPA多数据源配置 - 主数据源 + * @author: yangkai.shen + * @date: Created in 2019-01-17 15:58 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +public class PrimaryDataSourceConfig { + + /** + * 扫描spring.datasource.primary开头的配置信息 + * + * @return 数据源配置信息 + */ + @Primary + @Bean(name = "primaryDataSourceProperties") + @ConfigurationProperties(prefix = "spring.datasource.primary") + public DataSourceProperties dataSourceProperties() { + return new DataSourceProperties(); + } + + /** + * 获取主库数据源对象 + * + * @param dataSourceProperties 注入名为primaryDataSourceProperties的bean + * @return 数据源对象 + */ + @Primary + @Bean(name = "primaryDataSource") + public DataSource dataSource(@Qualifier("primaryDataSourceProperties") DataSourceProperties dataSourceProperties) { + return dataSourceProperties.initializeDataSourceBuilder().build(); + } + + /** + * 该方法仅在需要使用JdbcTemplate对象时选用 + * + * @param dataSource 注入名为primaryDataSource的bean + * @return 数据源JdbcTemplate对象 + */ + @Primary + @Bean(name = "primaryJdbcTemplate") + public JdbcTemplate jdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) { + return new JdbcTemplate(dataSource); + } + +} +``` + +## SecondDataSourceConfig.java + +> 从数据源配置 + +```java +/** + *+ * JPA多数据源配置 - 次数据源 + *
+ * + * @package: com.xkcoding.multi.datasource.jpa.config + * @description: JPA多数据源配置 - 次数据源 + * @author: yangkai.shen + * @date: Created in 2019-01-17 15:58 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +public class SecondDataSourceConfig { + + /** + * 扫描spring.datasource.second开头的配置信息 + * + * @return 数据源配置信息 + */ + @Bean(name = "secondDataSourceProperties") + @ConfigurationProperties(prefix = "spring.datasource.second") + public DataSourceProperties dataSourceProperties() { + return new DataSourceProperties(); + } + + /** + * 获取主库数据源对象 + * + * @param dataSourceProperties 注入名为secondDataSourceProperties的bean + * @return 数据源对象 + */ + @Bean(name = "secondDataSource") + public DataSource dataSource(@Qualifier("secondDataSourceProperties") DataSourceProperties dataSourceProperties) { + return dataSourceProperties.initializeDataSourceBuilder().build(); + } + + /** + * 该方法仅在需要使用JdbcTemplate对象时选用 + * + * @param dataSource 注入名为secondDataSource的bean + * @return 数据源JdbcTemplate对象 + */ + @Bean(name = "secondJdbcTemplate") + public JdbcTemplate jdbcTemplate(@Qualifier("secondDataSource") DataSource dataSource) { + return new JdbcTemplate(dataSource); + } + +} +``` + +## PrimaryJpaConfig.java + +> 主 JPA 配置 + +```java +/** + *+ * JPA多数据源配置 - 主 JPA 配置 + *
+ * + * @package: com.xkcoding.multi.datasource.jpa.config + * @description: JPA多数据源配置 - 主 JPA 配置 + * @author: yangkai.shen + * @date: Created in 2019-01-17 16:54 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + // repository包名 + basePackages = PrimaryJpaConfig.REPOSITORY_PACKAGE, + // 实体管理bean名称 + entityManagerFactoryRef = "primaryEntityManagerFactory", + // 事务管理bean名称 + transactionManagerRef = "primaryTransactionManager") +public class PrimaryJpaConfig { + static final String REPOSITORY_PACKAGE = "com.xkcoding.multi.datasource.jpa.repository.primary"; + private static final String ENTITY_PACKAGE = "com.xkcoding.multi.datasource.jpa.entity.primary"; + + + /** + * 扫描spring.jpa.primary开头的配置信息 + * + * @return jpa配置信息 + */ + @Primary + @Bean(name = "primaryJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.primary") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + /** + * 获取主库实体管理工厂对象 + * + * @param primaryDataSource 注入名为primaryDataSource的数据源 + * @param jpaProperties 注入名为primaryJpaProperties的jpa配置信息 + * @param builder 注入EntityManagerFactoryBuilder + * @return 实体管理工厂对象 + */ + @Primary + @Bean(name = "primaryEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("primaryJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) { + return builder + // 设置数据源 + .dataSource(primaryDataSource) + // 设置jpa配置 + .properties(jpaProperties.getProperties()) + // 设置实体包名 + .packages(ENTITY_PACKAGE) + // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源 + .persistenceUnit("primaryPersistenceUnit").build(); + } + + /** + * 获取实体管理对象 + * + * @param factory 注入名为primaryEntityManagerFactory的bean + * @return 实体管理对象 + */ + @Primary + @Bean(name = "primaryEntityManager") + public EntityManager entityManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + /** + * 获取主库事务管理对象 + * + * @param factory 注入名为primaryEntityManagerFactory的bean + * @return 事务管理对象 + */ + @Primary + @Bean(name = "primaryTransactionManager") + public PlatformTransactionManager transactionManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} +``` + +## SecondJpaConfig.java + +> 从 JPA 配置 + +```java +/** + *+ * JPA多数据源配置 - 次 JPA 配置 + *
+ * + * @package: com.xkcoding.multi.datasource.jpa.config + * @description: JPA多数据源配置 - 次 JPA 配置 + * @author: yangkai.shen + * @date: Created in 2019-01-17 16:54 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + // repository包名 + basePackages = SecondJpaConfig.REPOSITORY_PACKAGE, + // 实体管理bean名称 + entityManagerFactoryRef = "secondEntityManagerFactory", + // 事务管理bean名称 + transactionManagerRef = "secondTransactionManager") +public class SecondJpaConfig { + static final String REPOSITORY_PACKAGE = "com.xkcoding.multi.datasource.jpa.repository.second"; + private static final String ENTITY_PACKAGE = "com.xkcoding.multi.datasource.jpa.entity.second"; + + + /** + * 扫描spring.jpa.second开头的配置信息 + * + * @return jpa配置信息 + */ + @Bean(name = "secondJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.second") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + /** + * 获取主库实体管理工厂对象 + * + * @param secondDataSource 注入名为secondDataSource的数据源 + * @param jpaProperties 注入名为secondJpaProperties的jpa配置信息 + * @param builder 注入EntityManagerFactoryBuilder + * @return 实体管理工厂对象 + */ + @Bean(name = "secondEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("secondDataSource") DataSource secondDataSource, @Qualifier("secondJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) { + return builder + // 设置数据源 + .dataSource(secondDataSource) + // 设置jpa配置 + .properties(jpaProperties.getProperties()) + // 设置实体包名 + .packages(ENTITY_PACKAGE) + // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源 + .persistenceUnit("secondPersistenceUnit").build(); + } + + /** + * 获取实体管理对象 + * + * @param factory 注入名为secondEntityManagerFactory的bean + * @return 实体管理对象 + */ + @Bean(name = "secondEntityManager") + public EntityManager entityManager(@Qualifier("secondEntityManagerFactory") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + /** + * 获取主库事务管理对象 + * + * @param factory 注入名为secondEntityManagerFactory的bean + * @return 事务管理对象 + */ + @Bean(name = "secondTransactionManager") + public PlatformTransactionManager transactionManager(@Qualifier("secondEntityManagerFactory") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} +``` + +## application.yml + +```yaml +spring: + datasource: + primary: + url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8 + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.zaxxer.hikari.HikariDataSource + hikari: + minimum-idle: 5 + connection-test-query: SELECT 1 FROM DUAL + maximum-pool-size: 20 + auto-commit: true + idle-timeout: 30000 + pool-name: PrimaryHikariCP + max-lifetime: 60000 + connection-timeout: 30000 + second: + url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo-2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8 + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.zaxxer.hikari.HikariDataSource + hikari: + minimum-idle: 5 + connection-test-query: SELECT 1 FROM DUAL + maximum-pool-size: 20 + auto-commit: true + idle-timeout: 30000 + pool-name: SecondHikariCP + max-lifetime: 60000 + connection-timeout: 30000 + jpa: + primary: + show-sql: true + generate-ddl: true + hibernate: + ddl-auto: update + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL57InnoDBDialect + open-in-view: true + second: + show-sql: true + generate-ddl: true + hibernate: + ddl-auto: update + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL57InnoDBDialect + open-in-view: true +logging: + level: + com.xkcoding: debug + org.hibernate.SQL: debug + org.hibernate.type: trace +``` + +## SpringBootDemoMultiDatasourceJpaApplicationTests.java + +```java +package com.xkcoding.multi.datasource.jpa; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Snowflake; +import com.xkcoding.multi.datasource.jpa.entity.primary.PrimaryMultiTable; +import com.xkcoding.multi.datasource.jpa.entity.second.SecondMultiTable; +import com.xkcoding.multi.datasource.jpa.repository.primary.PrimaryMultiTableRepository; +import com.xkcoding.multi.datasource.jpa.repository.second.SecondMultiTableRepository; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +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 java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Slf4j +public class SpringBootDemoMultiDatasourceJpaApplicationTests { + @Autowired + private PrimaryMultiTableRepository primaryRepo; + @Autowired + private SecondMultiTableRepository secondRepo; + @Autowired + private Snowflake snowflake; + + @Test + public void testInsert() { + PrimaryMultiTable primary = new PrimaryMultiTable(snowflake.nextId(),"测试名称-1"); + primaryRepo.save(primary); + + SecondMultiTable second = new SecondMultiTable(); + BeanUtil.copyProperties(primary, second); + secondRepo.save(second); + } + + @Test + public void testUpdate() { + primaryRepo.findAll().forEach(primary -> { + primary.setName("修改后的"+primary.getName()); + primaryRepo.save(primary); + + SecondMultiTable second = new SecondMultiTable(); + BeanUtil.copyProperties(primary, second); + secondRepo.save(second); + }); + } + + @Test + public void testDelete() { + primaryRepo.deleteAll(); + + secondRepo.deleteAll(); + } + + @Test + public void testSelect() { + List