You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 17 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. # spring-boot-demo-multi-datasource-jpa
  2. > 此 demo 主要演示 Spring Boot 如何集成 JPA 的多数据源。
  3. ## pom.xml
  4. ```xml
  5. <?xml version="1.0" encoding="UTF-8"?>
  6. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  7. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  8. <modelVersion>4.0.0</modelVersion>
  9. <artifactId>spring-boot-demo-multi-datasource-jpa</artifactId>
  10. <version>1.0.0-SNAPSHOT</version>
  11. <packaging>jar</packaging>
  12. <name>spring-boot-demo-multi-datasource-jpa</name>
  13. <description>Demo project for Spring Boot</description>
  14. <parent>
  15. <groupId>com.xkcoding</groupId>
  16. <artifactId>spring-boot-demo</artifactId>
  17. <version>1.0.0-SNAPSHOT</version>
  18. </parent>
  19. <properties>
  20. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  21. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  22. <java.version>1.8</java.version>
  23. </properties>
  24. <dependencies>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-starter-test</artifactId>
  32. <scope>test</scope>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-starter-data-jpa</artifactId>
  37. </dependency>
  38. <dependency>
  39. <groupId>mysql</groupId>
  40. <artifactId>mysql-connector-java</artifactId>
  41. </dependency>
  42. <dependency>
  43. <groupId>cn.hutool</groupId>
  44. <artifactId>hutool-all</artifactId>
  45. </dependency>
  46. <dependency>
  47. <groupId>com.google.guava</groupId>
  48. <artifactId>guava</artifactId>
  49. </dependency>
  50. <dependency>
  51. <groupId>org.projectlombok</groupId>
  52. <artifactId>lombok</artifactId>
  53. <optional>true</optional>
  54. </dependency>
  55. </dependencies>
  56. <build>
  57. <finalName>spring-boot-demo-multi-datasource-jpa</finalName>
  58. <plugins>
  59. <plugin>
  60. <groupId>org.springframework.boot</groupId>
  61. <artifactId>spring-boot-maven-plugin</artifactId>
  62. </plugin>
  63. </plugins>
  64. </build>
  65. </project>
  66. ```
  67. ## PrimaryDataSourceConfig.java
  68. > 主数据源配置
  69. ```java
  70. /**
  71. * <p>
  72. * JPA多数据源配置 - 主数据源
  73. * </p>
  74. *
  75. * @author yangkai.shen
  76. * @date Created in 2019-01-17 15:58
  77. */
  78. @Configuration
  79. public class PrimaryDataSourceConfig {
  80. /**
  81. * 扫描spring.datasource.primary开头的配置信息
  82. *
  83. * @return 数据源配置信息
  84. */
  85. @Primary
  86. @Bean(name = "primaryDataSourceProperties")
  87. @ConfigurationProperties(prefix = "spring.datasource.primary")
  88. public DataSourceProperties dataSourceProperties() {
  89. return new DataSourceProperties();
  90. }
  91. /**
  92. * 获取主库数据源对象
  93. *
  94. * @param dataSourceProperties 注入名为primaryDataSourceProperties的bean
  95. * @return 数据源对象
  96. */
  97. @Primary
  98. @Bean(name = "primaryDataSource")
  99. public DataSource dataSource(@Qualifier("primaryDataSourceProperties") DataSourceProperties dataSourceProperties) {
  100. return dataSourceProperties.initializeDataSourceBuilder().build();
  101. }
  102. /**
  103. * 该方法仅在需要使用JdbcTemplate对象时选用
  104. *
  105. * @param dataSource 注入名为primaryDataSource的bean
  106. * @return 数据源JdbcTemplate对象
  107. */
  108. @Primary
  109. @Bean(name = "primaryJdbcTemplate")
  110. public JdbcTemplate jdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) {
  111. return new JdbcTemplate(dataSource);
  112. }
  113. }
  114. ```
  115. ## SecondDataSourceConfig.java
  116. > 从数据源配置
  117. ```java
  118. /**
  119. * <p>
  120. * JPA多数据源配置 - 次数据源
  121. * </p>
  122. *
  123. * @author yangkai.shen
  124. * @date Created in 2019-01-17 15:58
  125. */
  126. @Configuration
  127. public class SecondDataSourceConfig {
  128. /**
  129. * 扫描spring.datasource.second开头的配置信息
  130. *
  131. * @return 数据源配置信息
  132. */
  133. @Bean(name = "secondDataSourceProperties")
  134. @ConfigurationProperties(prefix = "spring.datasource.second")
  135. public DataSourceProperties dataSourceProperties() {
  136. return new DataSourceProperties();
  137. }
  138. /**
  139. * 获取主库数据源对象
  140. *
  141. * @param dataSourceProperties 注入名为secondDataSourceProperties的bean
  142. * @return 数据源对象
  143. */
  144. @Bean(name = "secondDataSource")
  145. public DataSource dataSource(@Qualifier("secondDataSourceProperties") DataSourceProperties dataSourceProperties) {
  146. return dataSourceProperties.initializeDataSourceBuilder().build();
  147. }
  148. /**
  149. * 该方法仅在需要使用JdbcTemplate对象时选用
  150. *
  151. * @param dataSource 注入名为secondDataSource的bean
  152. * @return 数据源JdbcTemplate对象
  153. */
  154. @Bean(name = "secondJdbcTemplate")
  155. public JdbcTemplate jdbcTemplate(@Qualifier("secondDataSource") DataSource dataSource) {
  156. return new JdbcTemplate(dataSource);
  157. }
  158. }
  159. ```
  160. ## PrimaryJpaConfig.java
  161. > 主 JPA 配置
  162. ```java
  163. /**
  164. * <p>
  165. * JPA多数据源配置 - 主 JPA 配置
  166. * </p>
  167. *
  168. * @author yangkai.shen
  169. * @date Created in 2019-01-17 16:54
  170. */
  171. @Configuration
  172. @EnableTransactionManagement
  173. @EnableJpaRepositories(
  174. // repository包名
  175. basePackages = PrimaryJpaConfig.REPOSITORY_PACKAGE,
  176. // 实体管理bean名称
  177. entityManagerFactoryRef = "primaryEntityManagerFactory",
  178. // 事务管理bean名称
  179. transactionManagerRef = "primaryTransactionManager")
  180. public class PrimaryJpaConfig {
  181. static final String REPOSITORY_PACKAGE = "com.xkcoding.multi.datasource.jpa.repository.primary";
  182. private static final String ENTITY_PACKAGE = "com.xkcoding.multi.datasource.jpa.entity.primary";
  183. /**
  184. * 扫描spring.jpa.primary开头的配置信息
  185. *
  186. * @return jpa配置信息
  187. */
  188. @Primary
  189. @Bean(name = "primaryJpaProperties")
  190. @ConfigurationProperties(prefix = "spring.jpa.primary")
  191. public JpaProperties jpaProperties() {
  192. return new JpaProperties();
  193. }
  194. /**
  195. * 获取主库实体管理工厂对象
  196. *
  197. * @param primaryDataSource 注入名为primaryDataSource的数据源
  198. * @param jpaProperties 注入名为primaryJpaProperties的jpa配置信息
  199. * @param builder 注入EntityManagerFactoryBuilder
  200. * @return 实体管理工厂对象
  201. */
  202. @Primary
  203. @Bean(name = "primaryEntityManagerFactory")
  204. public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("primaryJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {
  205. return builder
  206. // 设置数据源
  207. .dataSource(primaryDataSource)
  208. // 设置jpa配置
  209. .properties(jpaProperties.getProperties())
  210. // 设置实体包名
  211. .packages(ENTITY_PACKAGE)
  212. // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源
  213. .persistenceUnit("primaryPersistenceUnit").build();
  214. }
  215. /**
  216. * 获取实体管理对象
  217. *
  218. * @param factory 注入名为primaryEntityManagerFactory的bean
  219. * @return 实体管理对象
  220. */
  221. @Primary
  222. @Bean(name = "primaryEntityManager")
  223. public EntityManager entityManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) {
  224. return factory.createEntityManager();
  225. }
  226. /**
  227. * 获取主库事务管理对象
  228. *
  229. * @param factory 注入名为primaryEntityManagerFactory的bean
  230. * @return 事务管理对象
  231. */
  232. @Primary
  233. @Bean(name = "primaryTransactionManager")
  234. public PlatformTransactionManager transactionManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) {
  235. return new JpaTransactionManager(factory);
  236. }
  237. }
  238. ```
  239. ## SecondJpaConfig.java
  240. > 从 JPA 配置
  241. ```java
  242. /**
  243. * <p>
  244. * JPA多数据源配置 - 次 JPA 配置
  245. * </p>
  246. *
  247. * @author yangkai.shen
  248. * @date Created in 2019-01-17 16:54
  249. */
  250. @Configuration
  251. @EnableTransactionManagement
  252. @EnableJpaRepositories(
  253. // repository包名
  254. basePackages = SecondJpaConfig.REPOSITORY_PACKAGE,
  255. // 实体管理bean名称
  256. entityManagerFactoryRef = "secondEntityManagerFactory",
  257. // 事务管理bean名称
  258. transactionManagerRef = "secondTransactionManager")
  259. public class SecondJpaConfig {
  260. static final String REPOSITORY_PACKAGE = "com.xkcoding.multi.datasource.jpa.repository.second";
  261. private static final String ENTITY_PACKAGE = "com.xkcoding.multi.datasource.jpa.entity.second";
  262. /**
  263. * 扫描spring.jpa.second开头的配置信息
  264. *
  265. * @return jpa配置信息
  266. */
  267. @Bean(name = "secondJpaProperties")
  268. @ConfigurationProperties(prefix = "spring.jpa.second")
  269. public JpaProperties jpaProperties() {
  270. return new JpaProperties();
  271. }
  272. /**
  273. * 获取主库实体管理工厂对象
  274. *
  275. * @param secondDataSource 注入名为secondDataSource的数据源
  276. * @param jpaProperties 注入名为secondJpaProperties的jpa配置信息
  277. * @param builder 注入EntityManagerFactoryBuilder
  278. * @return 实体管理工厂对象
  279. */
  280. @Bean(name = "secondEntityManagerFactory")
  281. public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("secondDataSource") DataSource secondDataSource, @Qualifier("secondJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {
  282. return builder
  283. // 设置数据源
  284. .dataSource(secondDataSource)
  285. // 设置jpa配置
  286. .properties(jpaProperties.getProperties())
  287. // 设置实体包名
  288. .packages(ENTITY_PACKAGE)
  289. // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源
  290. .persistenceUnit("secondPersistenceUnit").build();
  291. }
  292. /**
  293. * 获取实体管理对象
  294. *
  295. * @param factory 注入名为secondEntityManagerFactory的bean
  296. * @return 实体管理对象
  297. */
  298. @Bean(name = "secondEntityManager")
  299. public EntityManager entityManager(@Qualifier("secondEntityManagerFactory") EntityManagerFactory factory) {
  300. return factory.createEntityManager();
  301. }
  302. /**
  303. * 获取主库事务管理对象
  304. *
  305. * @param factory 注入名为secondEntityManagerFactory的bean
  306. * @return 事务管理对象
  307. */
  308. @Bean(name = "secondTransactionManager")
  309. public PlatformTransactionManager transactionManager(@Qualifier("secondEntityManagerFactory") EntityManagerFactory factory) {
  310. return new JpaTransactionManager(factory);
  311. }
  312. }
  313. ```
  314. ## application.yml
  315. ```yaml
  316. spring:
  317. datasource:
  318. primary:
  319. 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
  320. username: root
  321. password: root
  322. driver-class-name: com.mysql.cj.jdbc.Driver
  323. type: com.zaxxer.hikari.HikariDataSource
  324. hikari:
  325. minimum-idle: 5
  326. connection-test-query: SELECT 1 FROM DUAL
  327. maximum-pool-size: 20
  328. auto-commit: true
  329. idle-timeout: 30000
  330. pool-name: PrimaryHikariCP
  331. max-lifetime: 60000
  332. connection-timeout: 30000
  333. second:
  334. 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
  335. username: root
  336. password: root
  337. driver-class-name: com.mysql.cj.jdbc.Driver
  338. type: com.zaxxer.hikari.HikariDataSource
  339. hikari:
  340. minimum-idle: 5
  341. connection-test-query: SELECT 1 FROM DUAL
  342. maximum-pool-size: 20
  343. auto-commit: true
  344. idle-timeout: 30000
  345. pool-name: SecondHikariCP
  346. max-lifetime: 60000
  347. connection-timeout: 30000
  348. jpa:
  349. primary:
  350. show-sql: true
  351. generate-ddl: true
  352. hibernate:
  353. ddl-auto: update
  354. properties:
  355. hibernate:
  356. dialect: org.hibernate.dialect.MySQL57InnoDBDialect
  357. open-in-view: true
  358. second:
  359. show-sql: true
  360. generate-ddl: true
  361. hibernate:
  362. ddl-auto: update
  363. properties:
  364. hibernate:
  365. dialect: org.hibernate.dialect.MySQL57InnoDBDialect
  366. open-in-view: true
  367. logging:
  368. level:
  369. com.xkcoding: debug
  370. org.hibernate.SQL: debug
  371. org.hibernate.type: trace
  372. ```
  373. ## SpringBootDemoMultiDatasourceJpaApplicationTests.java
  374. ```java
  375. package com.xkcoding.multi.datasource.jpa;
  376. import cn.hutool.core.bean.BeanUtil;
  377. import cn.hutool.core.lang.Snowflake;
  378. import com.xkcoding.multi.datasource.jpa.entity.primary.PrimaryMultiTable;
  379. import com.xkcoding.multi.datasource.jpa.entity.second.SecondMultiTable;
  380. import com.xkcoding.multi.datasource.jpa.repository.primary.PrimaryMultiTableRepository;
  381. import com.xkcoding.multi.datasource.jpa.repository.second.SecondMultiTableRepository;
  382. import lombok.extern.slf4j.Slf4j;
  383. import org.junit.Test;
  384. import org.junit.runner.RunWith;
  385. import org.springframework.beans.factory.annotation.Autowired;
  386. import org.springframework.boot.test.context.SpringBootTest;
  387. import org.springframework.test.context.junit4.SpringRunner;
  388. import java.util.List;
  389. @RunWith(SpringRunner.class)
  390. @SpringBootTest
  391. @Slf4j
  392. public class SpringBootDemoMultiDatasourceJpaApplicationTests {
  393. @Autowired
  394. private PrimaryMultiTableRepository primaryRepo;
  395. @Autowired
  396. private SecondMultiTableRepository secondRepo;
  397. @Autowired
  398. private Snowflake snowflake;
  399. @Test
  400. public void testInsert() {
  401. PrimaryMultiTable primary = new PrimaryMultiTable(snowflake.nextId(),"测试名称-1");
  402. primaryRepo.save(primary);
  403. SecondMultiTable second = new SecondMultiTable();
  404. BeanUtil.copyProperties(primary, second);
  405. secondRepo.save(second);
  406. }
  407. @Test
  408. public void testUpdate() {
  409. primaryRepo.findAll().forEach(primary -> {
  410. primary.setName("修改后的"+primary.getName());
  411. primaryRepo.save(primary);
  412. SecondMultiTable second = new SecondMultiTable();
  413. BeanUtil.copyProperties(primary, second);
  414. secondRepo.save(second);
  415. });
  416. }
  417. @Test
  418. public void testDelete() {
  419. primaryRepo.deleteAll();
  420. secondRepo.deleteAll();
  421. }
  422. @Test
  423. public void testSelect() {
  424. List<PrimaryMultiTable> primary = primaryRepo.findAll();
  425. log.info("【primary】= {}", primary);
  426. List<SecondMultiTable> second = secondRepo.findAll();
  427. log.info("【second】= {}", second);
  428. }
  429. }
  430. ```
  431. ## 目录结构
  432. ```
  433. .
  434. ├── README.md
  435. ├── pom.xml
  436. ├── spring-boot-demo-multi-datasource-jpa.iml
  437. ├── src
  438. │   ├── main
  439. │   │   ├── java
  440. │   │   │   └── com.xkcoding.multi.datasource.jpa
  441. │   │   │   ├── SpringBootDemoMultiDatasourceJpaApplication.java
  442. │   │   │   ├── config
  443. │   │   │   │   ├── PrimaryDataSourceConfig.java
  444. │   │   │   │   ├── PrimaryJpaConfig.java
  445. │   │   │   │   ├── SecondDataSourceConfig.java
  446. │   │   │   │   ├── SecondJpaConfig.java
  447. │   │   │   │   └── SnowflakeConfig.java
  448. │   │   │   ├── entity
  449. │   │   │   │   ├── primary
  450. │   │   │   │   │   └── PrimaryMultiTable.java
  451. │   │   │   │   └── second
  452. │   │   │   │   └── SecondMultiTable.java
  453. │   │   │   └── repository
  454. │   │   │   ├── primary
  455. │   │   │   │   └── PrimaryMultiTableRepository.java
  456. │   │   │   └── second
  457. │   │   │   └── SecondMultiTableRepository.java
  458. │   │   └── resources
  459. │   │   └── application.yml
  460. │   └── test
  461. │   └── java
  462. │   └── com.xkcoding.multi.datasource.jpa
  463. │   └── SpringBootDemoMultiDatasourceJpaApplicationTests.java
  464. └── target
  465. ```
  466. ## 参考
  467. 1. https://www.jianshu.com/p/34730e595a8c
  468. 2. https://blog.csdn.net/anxpp/article/details/52274120