实例讲解Spring boot动态切换数据源
摘要:本文模拟一下在主库查询订单信息查询不到的时候,切换数据源去历史库里面查询。
本文分享自华为云社区《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 boot动态切换数据源的更多相关文章
- Spring+Mybatis动态切换数据源
功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...
- Spring AOP动态切换数据源
现在稍微复杂一点的项目,一个数据库也可能搞不定,可能还涉及分布式事务什么的,不过由于现在我只是做一个接口集成的项目,所以分布式就先不用了,用Spring AOP来达到切换数据源,查询不同的数据库就可以 ...
- Spring MVC动态切换数据源(多数据库类型)
最近由于项目需求,需要将Sql Server 和 Mysql 两种数据库整合到一个项目,项目的用到的框架是SSM. 因此尝试了利用AOP切面来切每次执行的Servcie方法,根据Service所在的包 ...
- Spring Boot 如何动态切换数据源
本章是一个完整的 Spring Boot 动态数据源切换示例,例如主数据库使用 lionsea 从数据库 lionsea_slave1.lionsea_slave2.只需要在对应的代码上使用 Data ...
- 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法
相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...
- Spring + Mybatis 项目实现动态切换数据源
项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...
- Spring动态切换数据源及事务
前段时间花了几天来解决公司框架ssm上事务问题.如果不动态切换数据源话,直接使用spring的事务配置,是完全没有问题的.由于框架用于各个项目的快速搭建,少去配置各个数据源配置xml文件等.采用了动态 ...
- Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源
深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...
- Spring Boot配置多数据源并实现Druid自动切换
原文:https://blog.csdn.net/acquaintanceship/article/details/75350653 Spring Boot配置多数据源配置yml文件主数据源配置从数据 ...
- Spring Boot与多数据源那点事儿~
持续原创输出,点击上方蓝字关注我 目录 前言 写这篇文章的目的 什么是多数据源? 何时用到多数据源? 整合单一的数据源 整合Mybatis 多数据源如何整合? 什么是动态数据源? 数据源切换如何保证线 ...
随机推荐
- Java8 lambda常用操作
参考博客:https://www.cnblogs.com/hmy-1365/p/12923435.html
- InnoDB 索引深入剖析
InnoDB页 将数据划分为若干个页(page),以页作为磁盘和内存之间交互的基本单位,InnoDB中页的大小一般为 16KB.也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少 ...
- DES算法流程
初始置换IP 表格的使用方法: 将输入的64bit的明文从1开始标号,依次放入到IP初始置换表中数字对应的位置.填充完毕后,按照行优先的顺序从第1行开始依次读取获得输出. 16轮轮结构 整体结构 因为 ...
- 聊天小精灵ChatGPT,好与不好大揭秘!
一.引言 在一个遥远的地球上,有一个名为ChatGPT的魔法盒子,它能够用智慧回答你的问题,解决你的困扰.它是一个聪明的家伙,但和任何家伙一样,有优点也有缺点.现在就让我们一起来探索这个神秘的魔法盒子 ...
- 前端ffmpeg实现视频剪切
利用ffmpeg实现纯前端视频剪切 注意:在新版本Chrome浏览器中由于安全性问题,只能在https或localhost当中才能正常使用 1. 下载ffmpeg npm install @ffmpe ...
- 移动端网页--better-scroll介绍
移动端网页--better-scroll介绍 Options 起始位置及滚动方向 startX:0 开始时的X轴位置 startY:0 开始时的Y轴位置 scrollY: true 滚动方向为 Y 轴 ...
- python之wypy入门
wxPython入门 第一个应用程序:"Hello, World!" 按惯例,我们先来写一个 "Hello, World!" 小程序.这是代码: # -*- c ...
- [Linux]ln:软链接与硬链接
1 硬链接与软链接的[语法] 软链接:ln -s 源文件 目标文件 硬链接:ln 源文件 目标文件 [-s : symbolic,符号/代号] 2 软链接/硬链接的[比喻] / (编辑)同步性 [ro ...
- 【SSM项目】尚筹网(三)基于Servlet3.0项目搭建:异常映射和拦截器机制
1 异常映射 1.1 目标 使用异常映射对项目的异常和错误提示进行统一管理. 1.2 思路 对于普通的页面请求,异常映射机制捕获到handler方法抛出的异常后会响应为一个错误页面,对于处理ajax请 ...
- Yolov8离谱报错
YoloV8离谱报错 今天下午给一个研究生小姐姐跑数据集,用的是yolov8在恒源云上租的4070的GPU服务器,跑垃圾分类数据集(https://blog.csdn.net/m0_5488250 ...