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 + + + 4.0.0 + + spring-boot-demo-multi-datasource-jpa + 1.0.0-SNAPSHOT + jar + + spring-boot-demo-multi-datasource-jpa + Demo project for Spring Boot + + + com.xkcoding + spring-boot-demo + 1.0.0-SNAPSHOT + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + mysql + mysql-connector-java + + + + cn.hutool + hutool-all + + + + com.google.guava + guava + + + + org.projectlombok + lombok + true + + + + + spring-boot-demo-multi-datasource-jpa + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +``` + +## PrimaryDataSourceConfig.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 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 primary = primaryRepo.findAll(); + log.info("【primary】= {}", primary); + + List second = secondRepo.findAll(); + log.info("【second】= {}", second); + } + +} +``` + +## 目录结构 + +``` +. +├── README.md +├── pom.xml +├── spring-boot-demo-multi-datasource-jpa.iml +├── src +│   ├── main +│   │   ├── java +│   │   │   └── com.xkcoding.multi.datasource.jpa +│   │   │   ├── SpringBootDemoMultiDatasourceJpaApplication.java +│   │   │   ├── config +│   │   │   │   ├── PrimaryDataSourceConfig.java +│   │   │   │   ├── PrimaryJpaConfig.java +│   │   │   │   ├── SecondDataSourceConfig.java +│   │   │   │   ├── SecondJpaConfig.java +│   │   │   │   └── SnowflakeConfig.java +│   │   │   ├── entity +│   │   │   │   ├── primary +│   │   │   │   │   └── PrimaryMultiTable.java +│   │   │   │   └── second +│   │   │   │   └── SecondMultiTable.java +│   │   │   └── repository +│   │   │   ├── primary +│   │   │   │   └── PrimaryMultiTableRepository.java +│   │   │   └── second +│   │   │   └── SecondMultiTableRepository.java +│   │   └── resources +│   │   └── application.yml +│   └── test +│   └── java +│   └── com.xkcoding.multi.datasource.jpa +│   └── SpringBootDemoMultiDatasourceJpaApplicationTests.java +└── target +``` + +## 参考 + +1. https://www.jianshu.com/p/34730e595a8c +2. https://blog.csdn.net/anxpp/article/details/52274120 \ No newline at end of file diff --git a/spring-boot-demo-multi-datasource-jpa/pom.xml b/spring-boot-demo-multi-datasource-jpa/pom.xml index b689da9..0204b3f 100644 --- a/spring-boot-demo-multi-datasource-jpa/pom.xml +++ b/spring-boot-demo-multi-datasource-jpa/pom.xml @@ -25,7 +25,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter diff --git a/spring-boot-demo-multi-datasource-jpa/src/main/java/com/xkcoding/multi/datasource/jpa/config/SecondDataSourceConfig.java b/spring-boot-demo-multi-datasource-jpa/src/main/java/com/xkcoding/multi/datasource/jpa/config/SecondDataSourceConfig.java index 66afec3..4a79ddd 100644 --- a/spring-boot-demo-multi-datasource-jpa/src/main/java/com/xkcoding/multi/datasource/jpa/config/SecondDataSourceConfig.java +++ b/spring-boot-demo-multi-datasource-jpa/src/main/java/com/xkcoding/multi/datasource/jpa/config/SecondDataSourceConfig.java @@ -1,6 +1,5 @@ package com.xkcoding.multi.datasource.jpa.config; -import com.zaxxer.hikari.HikariDataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties;