翼度科技»论坛 编程开发 mysql 查看内容

实例讲解Spring boot动态切换数据源

9

主题

9

帖子

27

积分

新手上路

Rank: 1

积分
27
摘要:本文模拟一下在主库查询订单信息查询不到的时候,切换数据源去历史库里面查询。
本文分享自华为云社区《springboot动态切换数据源》,作者:小陈没烦恼 。
前言

在公司的系统里,由于数据量较大,所以配置了多个数据源,它会根据用户所在的地区去查询那一个数据库,这样就产生了动态切换数据源的场景。
今天,就模拟一下在主库查询订单信息查询不到的时候,切换数据源去历史库里面查询。
实现效果

首先我们设置查询的数据库为db1,可以看到通过订单号没有查到订单信息,然后我们重置数据源,重新设置为db2,同样的订单号就可以查询到信息。
数据库准备

新建两个数据库db1和db2,db1作为主库,db2作为历史库
两个库中都有一个订单表biz_order,主库中没有数据,历史库中有我们要查询的数据。
代码编写

1.新建一个springboot项目,引入所需依赖
  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>com.alibaba</groupId>
  7. <artifactId>druid-spring-boot-starter</artifactId>
  8. <version>1.2.15</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.mybatis.spring.boot</groupId>
  12. <artifactId>mybatis-spring-boot-starter</artifactId>
  13. <version>2.2.2</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>mysql</groupId>
  17. <artifactId>mysql-connector-java</artifactId>
  18. <version>8.0.30</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-test</artifactId>
  23. <scope>test</scope>
  24. </dependency>
复制代码
2.application.yaml配置数据库信息

这里我们配置两个数据库的信息
  1. spring:
  2. datasource:
  3.     db1:
  4.       driver-class-name: com.mysql.cj.jdbc.Driver
  5.       url: jdbc:mysql://localhost/db1?characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&failOverReadOnly=false
  6.       username: root
  7.       password: root
  8.       type: com.alibaba.druid.pool.DruidDataSource
  9.     db2:
  10.       driver-class-name: com.mysql.cj.jdbc.Driver
  11.       url: jdbc:mysql://localhost/db2?characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&failOverReadOnly=false
  12.       username: root
  13.       password: root
  14.       type: com.alibaba.druid.pool.DruidDataSource
  15. mybatis:
  16.   mapper-locations: classpath:mapper/*.xml
复制代码
3.创建数据源对象,并注入spring容器中

新建DynamicDataSourceConfig.java文件,在该配置文件中读取yaml配置的数据源信息,并且通过该信息构造数据源对象,然后通过@Bean注解注入到spring容器中。
  1. package com.it1997.config;
  2. import com.alibaba.druid.pool.DruidDataSource;
  3. import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
  4. import org.springframework.beans.factory.annotation.Qualifier;
  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.jdbc.datasource.DataSourceTransactionManager;
  9. import javax.sql.DataSource;
  10. @Configuration
  11. public class DynamicDataSourceConfig {
  12.     @Bean("dataSource1")
  13.     @ConfigurationProperties(prefix = "spring.datasource.db1")
  14. public DataSource oneDruidDataSource() {
  15. return DruidDataSourceBuilder.create().build();
  16. }
  17.     @Bean("dataSource2")
  18.     @ConfigurationProperties(prefix = "spring.datasource.db2")
  19. public DataSource twoDruidDataSource() {
  20. return DruidDataSourceBuilder.create().build();
  21. }
  22.     @Bean
  23. public DataSourceTransactionManager dataSourceTransactionManager1(@Qualifier("dataSource1") DataSource dataSource1) {
  24. DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
  25. dataSourceTransactionManager.setDataSource(dataSource1);
  26. return dataSourceTransactionManager;
  27. }
  28.     @Bean
  29. public DataSourceTransactionManager dataSourceTransactionManager2(@Qualifier("dataSource2") DataSource dataSource2) {
  30. DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
  31. dataSourceTransactionManager.setDataSource(dataSource2);
  32. return dataSourceTransactionManager;
  33. }
  34. }
复制代码
4.数据源配置上下文信息

新建DynamicDataSourceHolder.java文件,该文件通过ThreadLocal,实现为每一个线程创建一个保存数据源配置的上下文。并且提供setDataSource和getDataSource静态方法来设置和获取数据源的名称。
  1. package com.it1997.config;
  2. public class DynamicDataSourceHolder {
  3. private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
  4. public static void setDataSource(String dataSource) {
  5. contextHolder.set(dataSource);
  6. }
  7. public static String getDataSource() {
  8. return contextHolder.get();
  9. }
  10. public static void clearDataSource() {
  11. contextHolder.remove();
  12. }
  13. }
复制代码
5.重写数据源配置类

新建DynamicDataSource.java文件,该类继承AbstractRoutingDataSource 类,重写父类determineCurrentLookupKey和afterPropertiesSet方法。
这里我们重写父类中afterPropertiesSet方法(为什么要重写在这个方法,可以看文章最后对于druid的源码的讲解),在这个方法里我们将spring容器中的所有的数据源,都给放到map里,然后后续我们根据map中的key来获取不同的数据源,super.afterPropertiesSet();通过这个方法设置上数据源。
在类上加上@Primary注解,让spring容器优先使用我们自定义的数据源,否则还是会使用默认的数据源配置。
  1. package com.it1997.config;
  2. import org.springframework.context.annotation.Primary;
  3. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  4. import org.springframework.stereotype.Component;
  5. import javax.annotation.Resource;
  6. import javax.sql.DataSource;
  7. import java.util.HashMap;
  8. import java.util.Map;
  9. @Component
  10. @Primary
  11. public class DynamicDataSource extends AbstractRoutingDataSource {
  12.     @Resource
  13. DataSource dataSource1;
  14.     @Resource
  15. DataSource dataSource2;
  16.     @Override
  17. protected Object determineCurrentLookupKey() {
  18. return DynamicDataSourceHolder.getDataSource();
  19. }
  20.     @Override
  21. public void afterPropertiesSet() {
  22. // 初始化所有数据源
  23.         Map<Object, Object> targetDataSource = new HashMap<>();
  24. targetDataSource.put("db1", dataSource1);
  25. targetDataSource.put("db2", dataSource2);
  26. super.setTargetDataSources(targetDataSource);
  27. super.setDefaultTargetDataSource(dataSource1);
  28. super.afterPropertiesSet();
  29. }
  30. }
复制代码
druid数据源配置解读

点开我们刚刚继承的AbstractRoutingDataSource抽象类,可以看到它又继承了AbstractDataSource 实现了InitializingBean接口。
然后我们在看一下druid的数据源配置是怎么实现的,点开DruidDataSourceWrapper类,可以看到它也是继承了AbstractDataSource 实现了InitializingBean接口。并且,读取的是yaml文件中spring.datasource.druid下面配置的数据库连接信息。
而我们自定的一的数据源读取的是spring.datasource.db1下面配置的数据库连接信息。
druid的数据源配置,实现了接口中afterPropertiesSet,在这个方法中设置了数据库的基本信息,例如,数据库连接地址、用户名、密码以及数据库连接驱动信息。
 
点击关注,第一时间了解华为云新鲜技术~

来源:https://www.cnblogs.com/huaweiyun/p/17434200.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具