之前在介绍使用Spring-data-jpa时,都使用了单数据源。在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.properties文件中配置连接参数即可。但是往往随着业务量发展,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,下面基于Spring-data-jpa的例子介绍多数据源的配置方式。

springboot1.x jpa 配置多数据源(多数据源:大于等于2个数据库)

一、项目结构图(总体浏览一下最终完成后的建包样式)

java springboot 多数据源 springboot2多数据源配置_java

具体展开图(总体浏览一下最终完成后的建包样式):

java springboot 多数据源 springboot2多数据源配置_bc_02

 

 二、创建一个Spring配置类,定义两个DataSource用来读取application.properties中的不同配置。如下例子中,主数据源配置为spring.datasource.primary开头的配置,第二数据源配置为spring.datasource.secondary开头的配置。

java springboot 多数据源 springboot2多数据源配置_bc_03

【DataSourceConfig.java】

1 package com.didispace.config;
 2 
 3 import org.springframework.beans.factory.annotation.Qualifier;
 4 import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
 5 import org.springframework.boot.context.properties.ConfigurationProperties;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 import org.springframework.context.annotation.Primary;
 9 
10 import javax.sql.DataSource;
11 
12 @Configuration
13 public class DataSourceConfig {
14 
15     @Bean(name = "primaryDataSource")
16     @Qualifier("primaryDataSource")
17     @Primary
18     @ConfigurationProperties(prefix="spring.datasource.primary")
19     public DataSource primaryDataSource() {
20         return DataSourceBuilder.create().build();
21     }
22 
23     @Bean(name = "secondaryDataSource")
24     @Qualifier("secondaryDataSource")
25     @ConfigurationProperties(prefix="spring.datasource.secondary")
26     public DataSource secondaryDataSource() {
27         return DataSourceBuilder.create().build();
28     }
29 
30 }

对应的application.properties配置如下:

1 spring.datasource.primary.url=jdbc:mysql://localhost:3306/scott
 2 spring.datasource.primary.username=root
 3 spring.datasource.primary.password=root
 4 spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver
 5 
 6 spring.datasource.secondary.url=jdbc:mysql://localhost:3306/scott_2
 7 spring.datasource.secondary.username=root
 8 spring.datasource.secondary.password=root
 9 spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver
10 
11 #display sql in console,设置将每一条jpa指令都打印在控制台中
12 spring.jpa.show-sql=true
13 
14 spring.main.allow-bean-definition-overriding=true


三、数据源的JPA配置(几个数据源,几个相应名称匹配的配置,自己理解,后期尽量改成批量方式)

java springboot 多数据源 springboot2多数据源配置_java_04

【PrimaryConfig.java】

1 package com.didispace.config;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
 6 import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.context.annotation.Configuration;
 9 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
10 import org.springframework.orm.jpa.JpaTransactionManager;
11 import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
12 import org.springframework.transaction.PlatformTransactionManager;
13 import org.springframework.transaction.annotation.EnableTransactionManagement;
14 
15 import javax.persistence.EntityManager;
16 import javax.sql.DataSource;
17 import java.util.Map;
18 
19 @Configuration
20 @EnableTransactionManagement
21 @EnableJpaRepositories(
22         entityManagerFactoryRef = "entityManagerFactoryPrimary",
23         transactionManagerRef = "transactionManagerPrimary",
24         basePackages = {"com.didispace.repository.primary"}) //设置Repository所在位置
25 public class PrimaryConfig {
26 
27     @Autowired
28     @Qualifier("primaryDataSource")
29     private DataSource primaryDataSource;
30 
31     @Bean(name = "entityManagerPrimary")
32     public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
33         return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
34     }
35 
36     @Bean(name = "entityManagerFactoryPrimary")
37     public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
38         return builder
39                 .dataSource(primaryDataSource)
40                 .properties(getVendorProperties(primaryDataSource))
41                 .packages("com.didispace.entity.primary") //设置实体类所在位置
42                 .persistenceUnit("primaryPersistenceUnit")
43                 .build();
44     }
45 
46     @Autowired
47     private JpaProperties jpaProperties;
48 
49     private Map<String, String> getVendorProperties(DataSource dataSource) {
50         return jpaProperties.getHibernateProperties(dataSource);
51     }
52 
53     @Bean(name = "transactionManagerPrimary")
54     public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
55         return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
56     }
57 
58 }

【SecondaryConfig.java】

1 package com.didispace.config;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.beans.factory.annotation.Qualifier;
 5 import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
 6 import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.context.annotation.Configuration;
 9 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
10 import org.springframework.orm.jpa.JpaTransactionManager;
11 import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
12 import org.springframework.transaction.PlatformTransactionManager;
13 import org.springframework.transaction.annotation.EnableTransactionManagement;
14 
15 import javax.persistence.EntityManager;
16 import javax.sql.DataSource;
17 import java.util.Map;
18 
19 @Configuration
20 @EnableTransactionManagement
21 @EnableJpaRepositories(
22         entityManagerFactoryRef = "entityManagerFactorySecondary",
23         transactionManagerRef = "transactionManagerSecondary",
24         basePackages = {"com.didispace.repository.secondary"}) //设置Repository所在位置
25 public class SecondaryConfig {
26 
27     @Autowired
28     @Qualifier("secondaryDataSource")
29     private DataSource secondaryDataSource;
30 
31     @Bean(name = "entityManagerSecondary")
32     public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
33         return entityManagerFactorySecondary(builder).getObject().createEntityManager();
34     }
35 
36     @Bean(name = "entityManagerFactorySecondary")
37     public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {
38         return builder
39                 .dataSource(secondaryDataSource)
40                 .properties(getVendorProperties(secondaryDataSource))
41                 .packages("com.didispace.entity.secondary") //设置实体类所在位置
42                 .persistenceUnit("secondaryPersistenceUnit")
43                 .build();
44     }
45 
46     @Autowired
47     private JpaProperties jpaProperties;
48 
49     private Map<String, String> getVendorProperties(DataSource dataSource) {
50         return jpaProperties.getHibernateProperties(dataSource);
51     }
52 
53     @Bean(name = "transactionManagerSecondary")
54     PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
55         return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
56     }
57 
58 }

 

四、最后,分别在这两个包下创建各自的实体和数据访问接口

java springboot 多数据源 springboot2多数据源配置_java_05

测试如下:

编写测试代码:

1 package com.didispace;
 2 
 3 import com.didispace.entity.secondary.Salgrade;
 4 import com.didispace.repository.secondary.SalgradeRepository;
 5 import com.didispace.entity.primary.Dept;
 6 import com.didispace.repository.primary.DeptRepository;
 7 import org.junit.Before;
 8 import org.junit.Test;
 9 import org.junit.runner.RunWith;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.boot.test.SpringApplicationConfiguration;
12 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
13 
14 import java.util.Iterator;
15 import java.util.List;
16 
17 
18 @RunWith(SpringJUnit4ClassRunner.class)
19 @SpringApplicationConfiguration(Application.class)
20 public class ApplicationTests {
21 
22     @Autowired
23     private DeptRepository deptRepository;
24     @Autowired
25     private SalgradeRepository salgradeRepository;
26 
27     @Before
28     public void setUp() {
29     }
30 
31     @Test
32     public void test() throws Exception {
33 
34 
35         System.out.println("--- --- --- 结果如下 --- --- ---");
36         System.out.println("【数据库scott】");
37         List<Dept> ans = deptRepository.findByDname("FILL");
38         Iterator<Dept> it = ans.iterator();
39         while(it.hasNext()){
40             Dept d = it.next();
41             System.out.println(d);
42 
43         }
44 
45         System.out.println("--- --- --- --- --- --- --- --- ");
46         System.out.println("【数据库scott_2】");
47         Salgrade grade = salgradeRepository.findByGrade(1);
48         System.out.println(grade);
49     }
50 
51 
52 }

涉及的数据库表:

java springboot 多数据源 springboot2多数据源配置_bc_06

输出结果:

java springboot 多数据源 springboot2多数据源配置_bc_07

 

springboot2.x jpa 配置多数据源(多数据源:大于等于2个数据库)

随着Springboot升级到2.0,原来1.5.x的Jpa多数据源配置不能用了。现在总结一下Springboot2.0的jpa多数据源配置。

一、项目结构图(总体浏览一下最终完成后的建包样式)

java springboot 多数据源 springboot2多数据源配置_bc_08

 

二、创建一个Spring配置类,定义两个DataSource用来读取application.properties中的不同配置。如下例子中,主数据源配置为spring.datasource.primary开头的配置,第二数据源配置为spring.datasource.secondary开头的配置。

java springboot 多数据源 springboot2多数据源配置_bc_09

【DataSourceConfig.java】

1 package com.angei.day0924jpa.Config;
 2 
 3 import org.springframework.beans.factory.annotation.Qualifier;
 4 import org.springframework.boot.context.properties.ConfigurationProperties;
 5 import org.springframework.boot.jdbc.DataSourceBuilder;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 import org.springframework.context.annotation.Primary;
 9 
10 import javax.sql.DataSource;
11 
12 
13 @Configuration
14 public class DataSourceConfig {
15 
16     @Bean(name = "primaryDataSource")
17     @Qualifier("primaryDataSource")
18     @Primary
19     @ConfigurationProperties(prefix="spring.datasource.primary")
20     public DataSource primaryDataSource() {
21         return DataSourceBuilder.create().build();
22     }
23 
24     @Bean(name = "secondaryDataSource")
25     @Qualifier("secondaryDataSource")
26     @ConfigurationProperties(prefix="spring.datasource.secondary")
27     public DataSource secondaryDataSource() {
28         return DataSourceBuilder.create().build();
29     }
30 
31 }

对应的application.properties配置如下:

1 # 多数据源配置
 2 #primary
 3 spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/scott?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8
 4 spring.datasource.primary.username=root
 5 spring.datasource.primary.password=root
 6 spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
 7 
 8 #secondary
 9 spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/scott_2?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8
10 spring.datasource.secondary.username=root
11 spring.datasource.secondary.password=root
12 spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
13 
14 
15 #display sql in console,设置将每一条jpa指令都打印在控制台中
16 spring.jpa.show-sql=true
17 
18 spring.main.allow-bean-definition-overriding=true

注意:

关于异常提示:

java springboot 多数据源 springboot2多数据源配置_bc_10

 dataSource或dataSourceClassName或jdbcUrl是必需的!

解决方案:

将:

spring.datasource.primary.url=jdbc:mysql://IP地址/dbName

修改为:

spring.datasource.primary.jdbc-url=jdbc:mysql://IP地址/dbName

 

三、数据源的JPA配置(几个数据源,几个相应名称匹配的配置,自己理解,后期尽量改成批量方式)

java springboot 多数据源 springboot2多数据源配置_spring_11

【PrimaryConfig.java】

1 package com.angei.day0924jpa.Config;
 2 
 3 import org.springframework.beans.factory.annotation.Qualifier;
 4 import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Configuration;
 7 import org.springframework.context.annotation.Primary;
 8 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
 9 import org.springframework.orm.jpa.JpaTransactionManager;
10 import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
11 import org.springframework.transaction.PlatformTransactionManager;
12 import org.springframework.transaction.annotation.EnableTransactionManagement;
13 
14 import javax.annotation.Resource;
15 import javax.persistence.EntityManager;
16 import javax.sql.DataSource;
17 import java.util.Properties;
18 
19 
20 @Configuration
21 @EnableTransactionManagement
22 @EnableJpaRepositories(
23         entityManagerFactoryRef = "entityManagerFactoryPrimary",
24         transactionManagerRef = "transactionManagerPrimary",
25         basePackages = {"com.angei.day0924jpa.repository.primary"}) //设置Repository所在位置
26 
27 public class PrimaryConfig {
28 
29     @Resource
30     @Qualifier("primaryDataSource")
31     private DataSource primaryDataSource;
32 
33     @Primary
34     @Bean(name = "entityManagerPrimary")
35     public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
36         return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
37     }
38 
39     @Resource
40     private Properties jpaProperties;
41 
42 
43     @Primary
44     @Bean(name = "entityManagerFactoryPrimary")
45     public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
46         LocalContainerEntityManagerFactoryBean entityManagerFactory = builder
47                 .dataSource(primaryDataSource)
48                 .packages("com.angei.day0924jpa.entity.primary") //设置实体类所在位置
49                 .persistenceUnit("primaryPersistenceUnit")
50                 .build();
51         entityManagerFactory.setJpaProperties(jpaProperties);
52         return entityManagerFactory;
53     }
54 
55     @Primary
56     @Bean(name = "transactionManagerPrimary")
57     public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
58         return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
59     }
60 
61 }

【SecondaryConfig.java】

1 package com.angei.day0924jpa.Config;
 2 
 3 import org.springframework.beans.factory.annotation.Qualifier;
 4 import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Configuration;
 7 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
 8 import org.springframework.orm.jpa.JpaTransactionManager;
 9 import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
10 import org.springframework.transaction.PlatformTransactionManager;
11 import org.springframework.transaction.annotation.EnableTransactionManagement;
12 
13 import javax.annotation.Resource;
14 import javax.persistence.EntityManager;
15 import javax.sql.DataSource;
16 import java.util.Properties;
17 
18 
19 @Configuration
20 @EnableTransactionManagement
21 @EnableJpaRepositories(
22         entityManagerFactoryRef = "entityManagerFactorySecondary",
23         transactionManagerRef = "transactionManagerSecondary",
24         basePackages = {"com.angei.day0924jpa.repository.secondary"}) //设置Repository所在位置
25 public class SecondaryConfig {
26 
27     @Resource
28     @Qualifier("secondaryDataSource")
29     private DataSource secondaryDataSource;
30 
31     @Resource
32     private Properties jpaProperties;
33 
34 
35     @Bean(name = "entityManagerSecondary")
36     public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
37         return entityManagerFactorySecondary(builder).getObject().createEntityManager();
38     }
39 
40     @Bean(name = "entityManagerFactorySecondary")
41     public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {
42         LocalContainerEntityManagerFactoryBean entityManagerFactory
43                 = builder
44                 .dataSource(secondaryDataSource)
45                 .packages("com.angei.day0924jpa.entity.secondary") //设置实体类所在位置
46                 .persistenceUnit("secondaryPersistenceUnit")//持久化单元创建一个默认即可,多个便要分别命名
47                 .build();
48         entityManagerFactory.setJpaProperties(jpaProperties);
49         return entityManagerFactory;
50     }
51 
52     @Bean(name = "transactionManagerSecondary")
53     public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
54         return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
55     }
56 }

说明:从SpringBoot1.x 升级至SpringBoot2.1.x 上述配置做了如下的修改:

java springboot 多数据源 springboot2多数据源配置_java_12

四、最后,分别在这两个包下创建各自的实体和数据访问接口

java springboot 多数据源 springboot2多数据源配置_spring_13

测试如下:

编写测试代码:

【ContractController.java】

1 package com.angei.day0924jpa.controller;
 2 
 3 import com.angei.day0924jpa.entity.primary.Dept;
 4 import com.angei.day0924jpa.entity.secondary.Salgrade;
 5 import com.angei.day0924jpa.repository.primary.DeptRepository;
 6 import com.angei.day0924jpa.repository.secondary.SalgradeRepository;
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.stereotype.Controller;
 9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.ResponseBody;
11 
12 import java.util.Iterator;
13 import java.util.List;
14 
15 @Controller
16 @RequestMapping("/contract")
17 public class ContractController {
18 
19     @Autowired
20     private DeptRepository deptRepository;
21 
22     @Autowired
23     private SalgradeRepository salgradeRepository;
24 
25     @RequestMapping("/testing")
26     @ResponseBody
27     public void ContractQuery(){
28         System.out.println("【数据库1】");
29         List<Dept> ans = deptRepository.findByDname("FILL");
30         Iterator<Dept> it = ans.iterator();
31         while(it.hasNext()){
32 
33             Dept d = it.next();
34             System.out.println(d);
35         }
36         System.out.println("【数据库2】");
37         Salgrade res = salgradeRepository.findByGrade(2);
38         System.out.println(res);
39     }
40 }

访问:http://localhost:8080/contract/testing

显示如下:

java springboot 多数据源 springboot2多数据源配置_bc_14