基于Spring JDBC AbstractRoutingDataSource 实现动态数据源

AbstractRoutingDataSource 实现动态数据源

AbstractRoutingDataSource 即抽象的路由数据源,提供了动态数据源切换的机制。你可以通过实现它的 determineCurrentLookupKey() 方法,根据不同的条件返回对应的数据源 key,基于这点可以根据外部输入完成数据源的动态选择

路由数据源实现

基于ThreadLocal实现,每次选择数据源都根据ThreadLocal中的压测标识来决定是否走正常数据源还是压测数据源

package com.huakai.springenv.perf;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class TrafficRoutingDataSource extends AbstractRoutingDataSource {// ThreadLocal 用于存储当前请求是否是压测流量private static final ThreadLocal<Boolean> PRESSURE_TEST_FLAG = new ThreadLocal<>();// 设置压测标识public static void setPressureTestFlag(boolean isPressureTest) {PRESSURE_TEST_FLAG.set(isPressureTest);}// 清除压测标识public static void clearPressureTestFlag() {PRESSURE_TEST_FLAG.remove();}@Overrideprotected Object determineCurrentLookupKey() {// 根据 ThreadLocal 判断是否是压测流量Boolean isPressureTest = PRESSURE_TEST_FLAG.get();if (Boolean.TRUE.equals(isPressureTest)) {return "shadowDataSource";  // 返回影子库的数据源 key} else {return "primaryDataSource";  // 返回原始库的数据源 key}}
}

数据源配置

这里配置TrafficRoutingDataSource数据源,使用@Primary声明为Spring的默认数据源,并且将primaryDataSourceshadowDataSource添加到路由数据源列表

package com.huakai.springenv.perf;import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration
public class DataSourceConfig {@Bean@Primarypublic DataSource routingDataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource,@Qualifier("shadowDataSource") DataSource shadowDataSource) {TrafficRoutingDataSource routingDataSource = new TrafficRoutingDataSource();// 配置数据源Map<Object, Object> dataSourceMap = new HashMap<>();dataSourceMap.put("primaryDataSource", primaryDataSource);  // 主库dataSourceMap.put("shadowDataSource", shadowDataSource);    // 影子库routingDataSource.setTargetDataSources(dataSourceMap);routingDataSource.setDefaultTargetDataSource(primaryDataSource);  // 默认走主库routingDataSource.afterPropertiesSet();return routingDataSource;}// 配置主数据源和影子数据源@Beanpublic DataSource primaryDataSource() {HikariConfig hikariConfig = new HikariConfig();hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/test");  // 主库的 JDBC URLhikariConfig.setUsername("root");  // 数据库用户名hikariConfig.setPassword("123456");  // 数据库密码hikariConfig.setMaximumPoolSize(10);  // 最大连接池数hikariConfig.setMinimumIdle(0);return new HikariDataSource(hikariConfig);}@Beanpublic DataSource shadowDataSource() {HikariConfig hikariConfig = new HikariConfig();hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/perf__test");  // 从库的 JDBC URLhikariConfig.setUsername("root");  // 数据库用户名hikariConfig.setPassword("123456");  // 数据库密码hikariConfig.setMaximumPoolSize(10);  // 最大连接池数hikariConfig.setMinimumIdle(0);return new HikariDataSource(hikariConfig);}
}

基于过滤器实现压测流量自动选择影子库

过滤器

package com.huakai.springenv.perf;import org.springframework.stereotype.Component;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
public class PressureTestFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {try {HttpServletRequest request1 = (HttpServletRequest) request;// 通过请求中的 header 判断是否为压测流量String pressureTestHeader = request1.getHeader("X-Pressure-Test");if ("true".equals(pressureTestHeader)) {TrafficRoutingDataSource.setPressureTestFlag(true);}chain.doFilter(request, response);} finally {// 清理 ThreadLocalTrafficRoutingDataSource.clearPressureTestFlag();}}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}
}

过滤器配置

package com.huakai.springenv.perf;import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class WebConfig {@Beanpublic FilterRegistrationBean testFilterRegistration() {FilterRegistrationBean registration = new FilterRegistrationBean(new PressureTestFilter());registration.addUrlPatterns("/"); //registration.setName("perfFilter");return registration;}
}

web入口

package com.huakai.springenv.perf;import com.huakai.springenv.mapper.KvMapper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController()
@RequestMapping("perf")
public class PerfController {@Resourceprivate KvMapper kvMapper;@RequestMapping(value = "/test")public String test(@RequestParam String key) {return kvMapper.get(key).getValue();}
}

测试结果

正常流量走主库在这里插入图片描述
压测流量走影子库

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/432622.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 fwirte 函数 - C语言零基础入门教程

目录 一.fwirte 函数简介二.fwirte 函数使用三.猜你喜欢 零基础 C/C 学习路线推荐 : C/C 学习目录 >> C 语言基础入门 一.fwirte 函数简介 C 语言文件读写&#xff0c;fread 函数用于读取文件中的数据到指定缓冲区中&#xff0c;而 fwrite 函数用于把缓冲区数据写入到文件…

从1岁活到80岁很平凡 chatgpt 到底能干啥

有人说:一个人从1岁活到80岁很平凡,但如果从80岁倒着活,那么一半以上的人都可能不凡。 生活没有捷径,我们踩过的坑都成为了生活的经验,这些经验越早知道,你要走的弯路就会越少。 Introduction ChatGPT是一款基于人工智能技术的聊天机器人,可以自动回复用户的问题和提供…

【算法题】72. 编辑距离-力扣(LeetCode)

【算法题】72. 编辑距离-力扣(LeetCode) 1.题目 下方是力扣官方题目的地址 72. 编辑距离 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符删除一个字符替换一个…

公交IC卡收单管理系统 多处 SQL注入致RCE漏洞复现

0x01 产品简介 公交IC卡收单管理系统是城市公共交通领域中不可或缺的一部分,它通过集成先进的集成电路技术(IC卡)实现了乘客便捷的支付方式,并有效提高了公共交通运营效率。系统集成了发卡、充值、消费、数据采集、查询和注销等多个功能模块,为公交公司和乘客提供了全面、…

使用shardingsphere实现mysql数据库分片

在大数据时代&#xff0c;随着业务数据量的不断增长&#xff0c;单一的数据库往往难以承载大规模的数据处理需求。数据库分片&#xff08;Sharding&#xff09;是一种有效的数据库扩展技术&#xff0c;通过将数据分布到多个数据库实例上&#xff0c;提高系统的性能和可扩展性。…

详细解读,F5服务器负载均衡的技术优势

在现代大规模、高流量的网络使用场景中&#xff0c;为应对高并发和海量数据的挑战&#xff0c;服务器负载均衡技术应运而生。但凡知道服务器负载均衡这一名词的&#xff0c;基本都对F5有所耳闻&#xff0c;因为负载均衡正是F5的代表作&#xff0c;换句通俗易懂的话来说&#xf…

曲面构件的布尔运算

1.前言 布尔运算算法有多种&#xff0c;可以根据几何数据表达方式分为Brep布尔运算、CSG布尔运算、网格布尔运算等&#xff0c;而网格布尔运算又又多种&#xff0c;如BSP方式、八叉树方式&#xff0c;博主实现过Brep布尔运算、BSP和八叉树两种网格布尔运算。详细可参考博主文章…

threejs加载高度图渲染点云,不支持tiff

问题点 使用的point来渲染高度图点云&#xff0c;大数据图片无效渲染点多&#xff08;可以通过八叉树过滤掉无效点增加效率&#xff0c;这个太复杂&#xff09;&#xff0c;但是胜在简单能用 效果图 code 代码可运行&#xff0c;无需npm <!DOCTYPE html> <html la…

Springboot + netty + rabbitmq + myBatis+mysql流量消峰

目录 0.为什么用消息队列1.代码文件创建结构2.pom.xml文件3.三个配置文件开发和生产环境4.Rabbitmq 基础配置类 TtlQueueConfig5.建立netty服务器 + rabbitmq消息生产者6.建立常规队列的消费者 Consumer7.建立死信队列的消费者 DeadLetterConsumer8.建立mapper.xml文件9.建立ma…

使用 Higress AI 插件对接通义千问大语言模型

前言 什么是 AI Gateway AI Gateway 的定义是 AI Native 的 API Gateway&#xff0c;是基于 API Gateway 的能⼒来满⾜ AI Native 的需求。例如&#xff1a; 将传统的 QPS 限流扩展到 token 限流。将传统的负载均衡/重试/fallback 能力延伸&#xff0c;支持对接多个大模型厂…

Xcode16 iOS18 编译问题适配

问题1&#xff1a;ADClient编译报错问题 报错信息 Undefined symbols for architecture arm64:"_OBJC_CLASS_$_ADClient", referenced from:in ViewController.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit co…

【Redis】初识 Redis

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. Redis是什么2. 浅谈分布式3. Redis的特性3.1 在内存中存储3.2 可编程性3.3 扩展性3.4 持久化3.5 集群3.6 …

C++ 刷题 使用到的一些有用的容器和函数

优先队列 c优先队列priority_queue&#xff08;自定义比较函数&#xff09;_c优先队列自定义比较-CSDN博客 373. 查找和最小的 K 对数字 - 力扣&#xff08;LeetCode&#xff09; 官方题解&#xff1a; class Solution { public:vector<vector<int>> kSmallestP…

如何检测并阻止机器人活动

恶意机器人流量逐年增加&#xff0c;占 2023 年所有互联网流量的近三分之一。恶意机器人会访问敏感数据、实施欺诈、窃取专有信息并降低网站性能。新技术使欺诈者能够更快地发动攻击并造成更大的破坏。机器人的无差别和大规模攻击对所有行业各种规模的企业都构成风险。 但您的…

【含文档】基于Springboot+微信小程序 的高校二手商品交易平台(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

OJ在线评测系统 后端 判题机模块预开发 架构分析 使用工厂模式搭建

判题机模块预开发(架构师)(工厂模式) 判题机模块 是为了把代码交个代码沙箱去处理 得到结果返回 代码沙箱 梳理判题模块和代码沙箱的关系 判题模块&#xff1a;调用代码沙箱 把代码和输入交给代码沙箱去执行 代码沙箱&#xff1a;只负责接受代码和输入 返回编译的结果 不负…

用户态缓存:环形缓冲区(Ring Buffer)

目录 环形缓冲区&#xff08;Ring Buffer&#xff09;简介 为什么选择环形缓冲区&#xff1f; 代码解析 1. 头文件与类型定义 1.1 头文件保护符 1.2 包含必要的标准库 1.3 类型定义 2. 环形缓冲区结构体 2.1 结构体成员解释 3. 辅助宏与内联函数 3.1 min 宏 3.2 is…

Python办公自动化案例:将Excel数据批量保存到Word表格中

案例:将excel数据批量保存到Word表格中 要将Excel数据批量保存到Word表格中,可以使用Python的openpyxl库来读取Excel文件,以及python-docx库来创建和编辑Word文档。以下是一段示例代码,以及代码解释和一些注意事项。 准备好的Excel数据: 1.安装所需库 首先,确保你已经…

破局汽车智能化浪潮:Tire 1供应商的网络优化与升级策略

在汽车行业经历电动化、智能化的深刻变革中&#xff0c;Tier 1供应商正面临着前所未有的挑战与机遇。Tier 1 供应商&#xff0c;即一级供应商&#xff0c;是汽车产业链中占据关键地位的合作伙伴。这类供应商不仅直接向整车制造商提供核心总成和模块&#xff0c;还深度参与整车的…

通信工程学习:什么是PNF物理网络功能

PNF:物理网络功能 PNF(Physical Network Function)即物理网络功能,是指支持网络功能的物理设备。以下是关于PNF的详细解释: 一、定义与特点 定义: PNF是网络设备厂商(如Cisco、华为、H3C等)通过专用硬件实体提供软件功能的设备。这些设备直接在物理服务器上运…