前言
随着业务量发展,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,如:user一个库,business一个库。那么接下来我们就要考虑怎么去在spring boot中实现多个数据源的配置。
实现
-
建表
首先是建表语句,我们要建立两个数据库,并各库内新建一张表
user表
mysql> use `user`; mysql> select * from `user`; +----+-------+----------+ | id | name | password | +----+-------+----------+ | 1 | 用户A | ****** | +----+-------+----------+ 1 row in set
business表
mysql> use `business`; mysql> select * from `business`; +----+-------+-------------+ | id | name | description | +----+-------+-------------+ | 1 | 业务A | 业务A描述 | +----+-------+-------------+ 1 row in set
接下来我们通过代码实现对两个库内的多张表进行查询。
-
配置
首先,创建一个Spring配置类,定义两个DataSource用来读取
application.yml
中的不同配置。本文中,我们user做为主数据源,主数据源配置为spring.datasource.user
开头的配置,business数据源配置为spring.datasource.business
开头的配置。@Configuration public class DataSourceConfig { @Primary @Bean(name = "userDataSource") @Qualifier("userDataSource") @ConfigurationProperties(prefix = "spring.datasource.user") public DataSource userDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "businessDataSource") @Qualifier("businessDataSource") @ConfigurationProperties(prefix = "spring.datasource.business") public DataSource businessDataSource() { return DataSourceBuilder.create().build(); } }
对应的配置文件
application.yml
如下:spring: datasource: user: driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/user username: root password: 123456 business: driver-class-name: com.mysql.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/business username: root password: 123456
接下来我们对各数据源进行jpa的配置
主数据源User
@Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef = "entityManagerFactoryUser", transactionManagerRef = "transactionManagerUser", //设置Repository所在位置 basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.user"}) public class UserConfig { @Autowired @Qualifier("userDataSource") private DataSource userDataSource; @Autowired private JpaProperties jpaProperties; @Autowired private HibernateProperties hibernateProperties; @Primary @Bean(name = "entityManagerUser") public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactoryUser(builder).getObject().createEntityManager(); } @Primary @Bean(name = "entityManagerFactoryUser") public LocalContainerEntityManagerFactoryBean entityManagerFactoryUser(EntityManagerFactoryBuilder builder) { return builder .dataSource(userDataSource) //设置entity所在位置 .packages("com.ppc.spring.example.jpamultidatasource.entity.user") .persistenceUnit("userPersistenceUnit") .properties(getVendorProperties()) .build(); } private Map<String, Object> getVendorProperties() { return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings()); } @Primary @Bean(name = "transactionManagerUser") public PlatformTransactionManager transactionManagerUser(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryUser(builder).getObject()); } }
其他数据源business
@Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef = "entityManagerFactoryBusiness", transactionManagerRef = "transactionManagerBusiness", //设置repository所在位置 basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.business"}) public class BusinessConfig { @Autowired @Qualifier("businessDataSource") private DataSource businessDataSource; @Autowired private JpaProperties jpaProperties; @Autowired private HibernateProperties hibernateProperties; @Bean(name = "entityManagerBusiness") public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactoryBusiness(builder).getObject().createEntityManager(); } @Bean(name = "entityManagerFactoryBusiness") public LocalContainerEntityManagerFactoryBean entityManagerFactoryBusiness(EntityManagerFactoryBuilder builder) { return builder .dataSource(businessDataSource) .properties(getVendorProperties()) //设置实体类所在位置 .packages("com.ppc.spring.example.jpamultidatasource.entity.business") .persistenceUnit("businessPersistenceUnit") .build(); } private Map<String, Object> getVendorProperties() { return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings()); } @Bean(name = "transactionManagerBusiness") PlatformTransactionManager transactionManagerBusiness(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryBusiness(builder).getObject()); } }
配置中需要注意以下几点:
-
repository、entity的所在位置,要和实际保存的位置一致。
-
主数据源的一些配置需要添加
@Primary
作为spring默认的首选项,其他数据源无需添加该注解。 -
通过查看相关源码我们看到Spring Boot中
JpaProperties
的代码一直在调整,这里我们将properties相关代码单独提取出作为一个单独的方法getVendorProperties
展示版本间的区别。其中:-
Spring Boot 1.5.x
private Map<String, String> getVendorProperties() { return jpaProperties.getHibernateProperties(userDataSource); }
-
Spring Boot 2.0.x
private Map<String, Object> getVendorProperties() { return jpaProperties.getHibernateProperties(new HibernateSettings()); }
-
Spring Boot 2.1.0参见上文代码,引进了
HibernateProperties
。同时,在Spring Boot 2.1.0中默认的mysql-connector-java
版本为8.0.13,连接低版本mysql配置上比较繁琐,建议在配置文件中手动指定相应版本,如本文中指定5.1.46
这个版本。runtimeOnly('mysql:mysql-connector-java:5.1.46')
-
-
-
查询
完成了所有的配置,接下来我们就可以开始写个简单代码验证我们配置了
@RestController @SpringBootApplication public class JpaMultiDatasourceApplication { @Autowired UserRepository userRepository; @Autowired BusinessRepository businessRepository; public static void main(String[] args) { SpringApplication.run(JpaMultiDatasourceApplication.class, args); } @GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { return userRepository.findById(id).orElse(null); } @GetMapping("/business/{id}") public Business getBusiness(@PathVariable Long id) { return businessRepository.findById(id).orElse(null); } }
我们对外暴露了两个接口,分别访问
user表
、business表
确认可以正常获取数据。查询结果如下:请求:http://localhost:8080/user/1 结果:{"id":1,"name":"用户A","password":"******"} 请求:http://localhost:8080/business/1 结果:{"id":1,"name":"业务A","description":"业务A描述"}
就此,我们双数据源的配置和验证工作就完成了。