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

news2024/9/21 14:53:37

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();
    }

    @Override
    protected 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
    @Primary
    public 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;
    }

    // 配置主数据源和影子数据源
    @Bean
    public DataSource primaryDataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
        hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/test");  // 主库的 JDBC URL
        hikariConfig.setUsername("root");  // 数据库用户名
        hikariConfig.setPassword("123456");  // 数据库密码
        hikariConfig.setMaximumPoolSize(10);  // 最大连接池数
        hikariConfig.setMinimumIdle(0);
        return new HikariDataSource(hikariConfig);
    }

    @Bean
    public DataSource shadowDataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
        hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/perf__test");  // 从库的 JDBC URL
        hikariConfig.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 {

    @Override
    public 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 {
            // 清理 ThreadLocal
            TrafficRoutingDataSource.clearPressureTestFlag();
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public 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 {
    @Bean
    public 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 {
    @Resource
    private KvMapper kvMapper;

    @RequestMapping(value = "/test")
    public String test(@RequestParam String key) {
        return kvMapper.get(key).getValue();
    }
}

测试结果

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenRestry(一个Nginx集成工具)的安装与使用

文章目录 一、OpenRestry介绍1、什么是Nginx呢&#xff1f;2、Nginx的反向代理3、Nginx的作用4、什么是OpenRestry&#xff1f; 二、OpenRestry的安装三、OpenRestry中nginx的使用1、Ngnix可以当做web服务器2、Nginx中可以编写Lua脚本 一、OpenRestry介绍 要想了解什么是OpenR…

ChatGPT搭上langchain的知识库RAG应用,效果超预期

最近利用LangchainChatGPT实现了上传文档实现个人知识库应用的能力&#xff0c;效果比想象得要好。文末大家可以体验一下效果~~ 给大家大致介绍下实现方式&#xff0c;参考了Langchain chatchat。 一、LangchainChatGPT 1、概述 LangChain 是一个强大的框架&#xff0c;可以…

数据技术进化史:从数据仓库到数据中台再到数据飞轮的旅程

随着大数据时代的到来&#xff0c;数据已经成为企业的核心资产之一。在过去几十年间&#xff0c;数据技术也随之不断演进&#xff0c;从早期的数据仓库到近年来热门的数据中台&#xff0c;再到正在快速发展的数据飞轮概念&#xff0c;每一步都是技术革新的体现。 一、数据仓库&…

信息安全工程师(10)网络信息安全法律与政策文件

前言 网络信息安全法律与政策文件是保障网络安全、维护网络空间秩序、保护公民和组织合法权益的重要基石。 一、主要法律文件 《中华人民共和国网络安全法》 发布时间&#xff1a;2016年11月7日&#xff0c;由第十二届全国人民代表大会常务委员会第二十四次会议通过。主要内容&…

9。maven必备小技巧

&#xff08;1&#xff09;配置Maven加速时&#xff0c;除了settings之外&#xff0c;还可如下图所示&#xff0c;配置如下&#xff1a; 若想实现Maven加速&#xff0c;最重要的即User settings file。&#xff08;先修改settings.xml&#xff09; &#xff08;2&#xff09;当…

微服务容错及解决

学前必备知识 学之前我们要理解一些概念&#xff0c;之后我们会遇到QPS&#xff0c;并发量&#xff0c;线程等专有名词。 一文搞懂高并发性能指标&#xff1a;QPS、TPS、RT、并发数、吞吐量 - 知乎 (zhihu.com) 雪崩问题 1 是什么 在微服务远程调用的过程中&#xff0c;还…

【C++】—— stack queue deque

【C】—— stack & queue & deque 1 stack 与 queue 的函数接口2 适配器2.1 发现问题2.2 什么是适配器 3 stack 与 queue的模拟实现3.1 栈的基础框架3.2 栈的模拟实现3.3 队列的模拟实现 4 模板的按需实例化5 deque 的简单介绍5.1 vector 与list对比5.1.1 vector5.1.2 …

Spring Boot 3项目使用Swagger3教程

Spring Boot 3项目使用Swagger3教程 Swagger&#xff1a;自动生成接口文档 添加依赖(pom.xml) <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.1…

音视频入门基础:AAC专题(7)——FFmpeg源码中计算AAC裸流每个packet的size值的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…

零工市场小程序:推动零工市场建设

人力资源和社会保障部在2024年4月发布了标题为《地方推进零工市场建设经验做法》的文章。 零工市场小程序的功能 信息登记与发布 精准匹配、推送 在线沟通 权益保障 零工市场小程序作为一个找零工的渠道&#xff0c;在往后随着技术的发展和政策的支持下&#xff0c;功能必然…

自注意力与多头自注意力的区别

自注意力机制和多头自注意力机制在深度学习&#xff0c;尤其是Transformer模型中是核心组件。它们的主要区别在于如何处理输入信息和增强模型的表达能力。 1. 自注意力机制&#xff08;Self-Attention&#xff09; 自注意力机制的主要作用是让模型在处理每个输入元素时&#…

计算机人工智能前沿进展-大语言模型方向-2024-09-20

计算机人工智能前沿进展-大语言模型方向-2024-09-20 1. Multimodal Fusion with LLMs for Engagement Prediction in Natural Conversation Authors: Cheng Charles Ma, Kevin Hyekang Joo, Alexandria K. Vail, Sunreeta Bhattacharya, Alvaro Fern’andez Garc’ia, Kailan…

操作系统 | 学习笔记 | | 王道 | 5.1 I/O管理概述

5.1 I/O管理概述 5.1.1 I/O设备 注&#xff1a;块设备可以寻址&#xff0c;但是字符设备是不可寻址的 I/O设备是将数据输入到计算机中&#xff0c;或者可以接收计算机输出数据的外部设备&#xff0c;属于计算机中的硬件部件&#xff1b; 设备的分类 按使用特性分类&#xff…

新手爬虫er必刷!如何使用代理IP全攻略!

在爬虫开发中&#xff0c;代理IP&#xff08;也称为代理服务器&#xff09;是一个非常重要的工具。当爬虫访问网站时&#xff0c;可能会遭遇IP封锁或请求频率限制。通过使用代理IP&#xff0c;可以分散请求压力并规避特定对IP的限制&#xff0c;从而提高采集任务的持续性。同时…

Cassandra 5.0 Spring Boot 3.3 CRUD

概览 因AI要使用到向量存储&#xff0c;JanusGraph也使用到Cassandra 卸载先前版本 docker stop cassandra && docker remove cassandra && rm -rf cassandra/运行Cassandra容器 docker run \--name cassandra \--hostname cassandra \-p 9042:9042 \--pri…

SpringCloud Alibaba五大组件之——Sentinel

SpringCloud Alibaba五大组件之——Sentinel&#xff08;文末附有完整项目GitHub链接&#xff09; 前言一、什么是Sentinel二、Sentinel控制台1.下载jar包2.自己打包3.启动控制台4.浏览器访问 三、项目中引入Sentinel1.在api-service模块的pom文件引入依赖&#xff1a;2.applic…

【干货整理】什么软件能监控员工电脑?六大好用的电脑监控软件,抢手推荐!

什么软件能监控员工电脑&#xff1f; 电脑监控软件啦&#xff01; 要是能有一双无形的眼睛&#xff0c;既监督员工的工作状态&#xff0c;又保护着公司的数据安全&#xff0c;这无疑是企业管理者的福音。 今天&#xff0c;我们就来一起探索那些能够精准助力、高效护航的六大电…

张养浩,文坛政坛的双重巨匠

张养浩&#xff0c;字希孟&#xff0c;号云庄&#xff0c;又称齐东野人&#xff0c;生于元世祖至元七年&#xff08;公元1270年&#xff09;&#xff0c;卒于元英宗至治三年&#xff08;公元1329年&#xff09;&#xff0c;享年59岁。他是中国元代著名的文学家、政治家&#xf…

【Linux】解锁系统编程奥秘,高效文件IO的实战技巧

文件 1. 知识铺垫2. C文件I/O2.1. C文件接口2.2 fopen()与重定向2.3. 当前路径2.4. stdin、stdout、stderr 3. 系统文件I/O3.1. 前言3.2. open3.2.1. flags</h3>3.2.2. mode</h3>3.2.3. 返回值fd 3.3. write</h2>3.4. read3.5. close</h2>3.6. lseek&l…

快速响应:提升前端页面加载速度技巧的必知策略方案

在本文中&#xff0c;我们将深入探讨导致页面加载缓慢的常见原因&#xff0c;并分享一系列切实可行的优化策略&#xff0c;无论你是刚入门的新手&#xff0c;还是经验丰富的开发者&#xff0c;这些技巧都将帮助你提升网页性能&#xff0c;让你的用户体验畅快无阻。 相信作为前端…