以前在介绍使用Spring-data-jpa时,都使用了单数据源。在单数据源的状况下,Spring Boot的配置很是简单,只须要在application.properties
文件中配置链接参数便可。可是每每随着业务量发展,咱们一般会进行数据库拆分或是引入其余数据库,从而咱们须要配置多个数据源,下面基于Spring-data-jpa的例子介绍多数据源的配置方式。java
1、项目结构图(整体浏览一下最终完成后的建包样式)mysql
具体展开图(整体浏览一下最终完成后的建包样式):web
2、建立一个Spring配置类,定义两个DataSource用来读取application.properties中
的不一样配置。以下例子中,主数据源配置为spring.datasource.primary
开头的配置,第二数据源配置为spring.datasource.secondary
开头的配置。spring
【DataSourceConfig.java】sql
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
3、数据源的JPA配置(几个数据源,几个相应名称匹配的配置,本身理解,后期尽可能改为批量方式)springboot
【PrimaryConfig.java】app
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 }
4、最后,分别在这两个包下建立各自的实体和数据访问接口ui
测试以下:
编写测试代码:
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 }
涉及的数据库表:
输出结果:
随着Springboot升级到2.0,原来1.5.x的Jpa多数据源配置不能用了。如今总结一下Springboot2.0的jpa多数据源配置。
1、项目结构图(整体浏览一下最终完成后的建包样式)
2、建立一个Spring配置类,定义两个DataSource用来读取application.properties中
的不一样配置。以下例子中,主数据源配置为spring.datasource.primary
开头的配置,第二数据源配置为spring.datasource.secondary
开头的配置。
【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
注意:
关于异常提示:
dataSource或dataSourceClassName或jdbcUrl是必需的!
解决方案:
将:
spring.datasource.primary.url=jdbc:mysql://IP地址/dbName
修改成:
spring.datasource.primary.jdbc-url=jdbc:mysql://IP地址/dbName
3、数据源的JPA配置(几个数据源,几个相应名称匹配的配置,本身理解,后期尽可能改为批量方式)
【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 上述配置作了以下的修改:
4、最后,分别在这两个包下建立各自的实体和数据访问接口
测试以下:
编写测试代码:
【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
显示以下: