首页 > 其他分享 >实例讲解Spring boot动态切换数据源

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

时间:2023-05-26 11:11:45浏览次数:54  
标签:Spring spring org boot 数据源 import public

摘要:本文模拟一下在主库查询订单信息查询不到的时候,切换数据源去历史库里面查询。

本文分享自华为云社区《springboot动态切换数据源》,作者:小陈没烦恼 。

前言

在公司的系统里,由于数据量较大,所以配置了多个数据源,它会根据用户所在的地区去查询那一个数据库,这样就产生了动态切换数据源的场景。

今天,就模拟一下在主库查询订单信息查询不到的时候,切换数据源去历史库里面查询。

实现效果

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

数据库准备

新建两个数据库db1和db2,db1作为主库,db2作为历史库

两个库中都有一个订单表biz_order,主库中没有数据,历史库中有我们要查询的数据。

代码编写

1.新建一个springboot项目,引入所需依赖

 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter</artifactId>
 </dependency>
 <!--引入druid-替换默认数据库连接池-->
 <dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>druid-spring-boot-starter</artifactId>
 <version>1.2.15</version>
 </dependency>
 <dependency>
 <groupId>org.mybatis.spring.boot</groupId>
 <artifactId>mybatis-spring-boot-starter</artifactId>
 <version>2.2.2</version>
 </dependency>
 <!--mysql驱动-->
 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>8.0.30</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
 </dependency>

2.application.yaml配置数据库信息

这里我们配置两个数据库的信息

spring:
 datasource:
    db1:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost/db1?characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&failOverReadOnly=false
      username: root
      password: root
      type: com.alibaba.druid.pool.DruidDataSource
    db2:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost/db2?characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&failOverReadOnly=false
      username: root
      password: root
      type: com.alibaba.druid.pool.DruidDataSource
mybatis:
  mapper-locations: classpath:mapper/*.xml

3.创建数据源对象,并注入spring容器中

新建DynamicDataSourceConfig.java文件,在该配置文件中读取yaml配置的数据源信息,并且通过该信息构造数据源对象,然后通过@Bean注解注入到spring容器中。

package com.it1997.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
public class DynamicDataSourceConfig {
    @Bean("dataSource1")
    @ConfigurationProperties(prefix = "spring.datasource.db1")
 public DataSource oneDruidDataSource() {
 return DruidDataSourceBuilder.create().build();
 }
    @Bean("dataSource2")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
 public DataSource twoDruidDataSource() {
 return DruidDataSourceBuilder.create().build();
 }
    @Bean
 public DataSourceTransactionManager dataSourceTransactionManager1(@Qualifier("dataSource1") DataSource dataSource1) {
 DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
 dataSourceTransactionManager.setDataSource(dataSource1);
 return dataSourceTransactionManager;
 }
    @Bean
 public DataSourceTransactionManager dataSourceTransactionManager2(@Qualifier("dataSource2") DataSource dataSource2) {
 DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
 dataSourceTransactionManager.setDataSource(dataSource2);
 return dataSourceTransactionManager;
 }
}

4.数据源配置上下文信息

新建DynamicDataSourceHolder.java文件,该文件通过ThreadLocal,实现为每一个线程创建一个保存数据源配置的上下文。并且提供setDataSource和getDataSource静态方法来设置和获取数据源的名称。

package com.it1997.config;
public class DynamicDataSourceHolder {
 private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
 public static void setDataSource(String dataSource) {
 contextHolder.set(dataSource);
 }
 public static String getDataSource() {
 return contextHolder.get();
 }
 public static void clearDataSource() {
 contextHolder.remove();
 }
}

5.重写数据源配置类

新建DynamicDataSource.java文件,该类继承AbstractRoutingDataSource 类,重写父类determineCurrentLookupKey和afterPropertiesSet方法。

这里我们重写父类中afterPropertiesSet方法(为什么要重写在这个方法,可以看文章最后对于druid的源码的讲解),在这个方法里我们将spring容器中的所有的数据源,都给放到map里,然后后续我们根据map中的key来获取不同的数据源,super.afterPropertiesSet();通过这个方法设置上数据源。

在类上加上@Primary注解,让spring容器优先使用我们自定义的数据源,否则还是会使用默认的数据源配置。

package com.it1997.config;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Resource
 DataSource dataSource1;
    @Resource
 DataSource dataSource2;
    @Override
 protected Object determineCurrentLookupKey() {
 return DynamicDataSourceHolder.getDataSource();
 }
    @Override
 public void afterPropertiesSet() {
 // 初始化所有数据源
        Map<Object, Object> targetDataSource = new HashMap<>();
 targetDataSource.put("db1", dataSource1);
 targetDataSource.put("db2", dataSource2);
 super.setTargetDataSources(targetDataSource);
 super.setDefaultTargetDataSource(dataSource1);
 super.afterPropertiesSet();
 }
}

druid数据源配置解读

点开我们刚刚继承的AbstractRoutingDataSource抽象类,可以看到它又继承了AbstractDataSource 实现了InitializingBean接口。

然后我们在看一下druid的数据源配置是怎么实现的,点开DruidDataSourceWrapper类,可以看到它也是继承了AbstractDataSource 实现了InitializingBean接口。并且,读取的是yaml文件中spring.datasource.druid下面配置的数据库连接信息。

而我们自定的一的数据源读取的是spring.datasource.db1下面配置的数据库连接信息。

druid的数据源配置,实现了接口中afterPropertiesSet,在这个方法中设置了数据库的基本信息,例如,数据库连接地址、用户名、密码以及数据库连接驱动信息。

 

点击关注,第一时间了解华为云新鲜技术~

标签:Spring,spring,org,boot,数据源,import,public
From: https://www.cnblogs.com/huaweiyun/p/17434200.html

相关文章

  • Spring Security 常见错误
    案例1:遗忘PasswordEncoder当我们第一次尝试使用SpringSecurity时,我们经常会忘记定义一个PasswordEncoder。因为这在SpringSecurity旧版本中是允许的。而一旦使用了新版本,则必须要提供一个PasswordEncoder。这里我们可以先写一个反例来感受下:(https://www.java567.com,搜......
  • idea显示springboot多服务启动界面service
    如果是多模块的微服务,idea提供了一个可以多服务启动的界面services,如果你的项目里没看到这个界面:那么你需要在顶级的maven工程中找到这个配置,然后找到componentname="RunDashboard"这个节点整个替换掉:<componentname="RunDashboard"><optionname="configurationTypes">......
  • SpeingBoot集成Redis和Redis的五种类型数据
    目录Springboot集成redisredis-cli的一些小知识点Springboot集成redismaven配置:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>配置redisTemplate,因为只操作字符串......
  • SpringBoot2.0实现SpringCloud config自动刷新之坑点
    在使用rabbitmq之后并不能实现客户端的配置自动刷新,原因是我参考的资料都是springboot1.x的,Springboot2.0的改动较大,之前1.0的/bus/refresh全部整合到actuador里面了,所以之前1.x的management.security.enabled全部失效,不适用于2.0适用于2.0的配置是这样的:management:endpoin......
  • Springboot+Vue集成个人中心、修改头像、数据联动、修改密码
    源码:https://gitee.com/xqnode/pure-design/tree/master学习视频:https://www.bilibili.com/video/BV1U44y1W77D开始讲解个人信息的下拉菜单:<el-dropdownstyle="width:150px;cursor:pointer;text-align:right"><divstyle="display:inline-block">......
  • Springboot集成百度地图实现定位打卡功能
    打卡sign表sqlCREATETABLE`sign`(`id`int(11)NOTNULLAUTO_INCREMENT,`user`varchar(255)COLLATEutf8mb4_unicode_ciDEFAULTNULLCOMMENT'用户名称',`location`varchar(255)COLLATEutf8mb4_unicode_ciDEFAULTNULLCOMMENT'打卡位置',`......
  • SpringBoot集成swagger-ui以及swagger分组显示
    文章目录1.swagger配置类2.使用swagger3.额外的学习经历大家好,这篇文章展示下如何在springboot项目中集成swagger-ui。有人说,这都是老生常谈,网上的例子数不胜数。确实swagger诞生至今已经很久了,但是在使用过程中我遇到一个问题,下面给大家分享下我的使用心得吧。1.swagger配置类第......
  • Springboot集成支付宝沙箱支付补充版本(退款功能)
    接上一次讲解:B站视频讲解:https://www.bilibili.com/video/BV1w44y1379q/这次的讲解涉及到完整的支付流程,大家请仔细查看!包括:支付宝沙箱支付+异步通知+退款功能正式版本的sdk通用版本SDK文档:https://opendocs.alipay.com/open/02np94<dependency><groupId>com.alipay.sdk......
  • Spring Web 参数验证常见错误
    案例1:对象参数校验失效在构建Web服务时,我们一般都会对一个HTTP请求的Body内容进行校验,例如我们来看这样一个案例及对应代码。当开发一个学籍管理系统时,我们会提供了一个API接口去添加学生的相关信息,其对象定义参考下面的代码:(https://www.java567.com,搜"spring") importlo......
  • spring boot框架JAVA语言实现的货运系统(司机APP端+货主APP端)
    技术架构:springboot、mybatis、redis、vue、element-ui  开发语言:java、vue、uniapp开发工具:idea、vscode、hbuilder+  前端框架:vue  后端框架:springboot  数据库:mysql  移动端:uniapp混合开发+原生插件后台管理端功能:权限设置:角色设置、人员设置......