SpringBoot3 + Jedis5 + Redis集群 如何通过scan方法分页获取所有keys
背景:
由于需要升级老项目代码,从SpringBoot1.5.x 升级到 SpringBoot3.3.x,框架中引用的Jedis自动升级到了 5.x;正好代码中有需要获取Redis集群的所有keys的需求存在;代码就不适用了,修改如下:
POM
由于默认是lettuce,需要手动添加jedis客户端
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><!-- 不依赖Redis的异步客户端lettuce --><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency>
Jedis3.x写法
public Set<String> keys(String pattern) {Set<String> set = new HashSet<>();JedisClusterConnection jedisClusterConnection = (JedisClusterConnection) redisTemplate.getConnectionFactory().getClusterConnection();//这里是获取jedispool的另外一种方式与上边的pipline可以对比下,两种方式都可以实现Map<String, JedisPool> clusterNodes = jedisClusterConnection.getNativeConnection().getClusterNodes();for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {//获取单个的jedis对象Jedis jedis = entry.getValue().getResource();// 判断非从节点(因为若主从复制,从节点会跟随主节点的变化而变化),此处要使用主节点, 从主节点获取数据if (!jedis.info("replication").contains("role:slave")) {Set<String> keys = getScan(jedis, pattern);if (keys.size() > 0) {Map<Integer, Set<String>> map = new HashMap<>(8);//接下来的循环不是多余的,需要注意for (String key : keys) {// cluster模式执行多key操作的时候,这些key必须在同一个slot上,不然会报:JedisDataException:int slot = JedisClusterCRC16.getSlot(key);// 按slot将key分组,相同slot的key一起提交if (map.containsKey(slot)) {map.get(slot).add(key);} else {Set<String> set1 = new HashSet<>();set1.add(key);map.put(slot, set1);}}for (Map.Entry<Integer, Set<String>> integerListEntry : map.entrySet()) {set.addAll(integerListEntry.getValue());}}}}return set;}@SuppressWarnings({ "rawtypes", "unchecked" })public Set<String> getScan(Jedis jedis, String key) {Set<String> set = new HashSet<>();//扫描的参数对象创建与封装ScanParams params = new ScanParams();params.match(key);//扫描返回一百行,这里可以根据业务需求进行修改params.count(1000);String cursor = "0";ScanResult scanResult = jedis.scan(cursor, params);//scan.getStringCursor() 存在 且不是 0 的时候,一直移动游标获取while (null != scanResult.getCursor()) {//封装扫描的结果set.addAll(scanResult.getResult());if (!"0".equals(scanResult.getCursor())) {scanResult = jedis.scan(scanResult.getCursor(), params);} else {break;}}return set;}
Jedis5.x写法
/*** 获取符合条件的key* @param pattern 表达式* @return*/public Set<String> keys(String pattern) {Set<String> set = new HashSet<>();JedisClusterConnection jedisClusterConnection = (JedisClusterConnection) redisTemplate.getConnectionFactory().getClusterConnection();Map<String, ConnectionPool> clusterNodes = ((JedisCluster) jedisClusterConnection.getNativeConnection()).getClusterNodes();// 看源码获取 key就是 host:port格式Set<String> nodes = clusterNodes.keySet();for (String node : nodes) {HostAndPort nodeObj = HostAndPort.from(node);try (Jedis jedis = new Jedis(nodeObj.getHost(), nodeObj.getPort())) { // try-with-resources可以自动关闭资源String roleInfo = jedis.info("replication");if (roleInfo.contains("role:master")) {Set<String> keys = getScan(jedis, pattern);if (keys.size() > 0) {Map<Integer, Set<String>> map = new HashMap<>(8);//接下来的循环不是多余的,需要注意for (String key : keys) {// cluster模式执行多key操作的时候,这些key必须在同一个slot上,不然会报:JedisDataException:int slot = JedisClusterCRC16.getSlot(key);// 按slot将key分组,相同slot的key一起提交if (map.containsKey(slot)) {map.get(slot).add(key);} else {Set<String> set1 = new HashSet<>();set1.add(key);map.put(slot, set1);}}for (Map.Entry<Integer, Set<String>> integerListEntry : map.entrySet()) {set.addAll(integerListEntry.getValue());}}}} catch (Exception e) {logger.error("redis连接错误:", e);}}return set;}@SuppressWarnings({ "rawtypes", "unchecked" })public Set<String> getScan(Jedis jedis, String key) {Set<String> set = new HashSet<>();//扫描的参数对象创建与封装ScanParams params = new ScanParams();params.match(key);//扫描返回一百行,这里可以根据业务需求进行修改params.count(1000);String cursor = "0";ScanResult scanResult = jedis.scan(cursor, params);//scan.getStringCursor() 存在 且不是 0 的时候,一直移动游标获取while (null != scanResult.getCursor()) {//封装扫描的结果set.addAll(scanResult.getResult());if (!"0".equals(scanResult.getCursor())) {scanResult = jedis.scan(scanResult.getCursor(), params);} else {break;}}return set;}
如上几句代码修改,搞了一下午,特此记录,以备查看!
问题原因与思路
由于
Map<String, JedisPool> clusterNodes = jedisClusterConnection.getNativeConnection().getClusterNodes();
被修改为:
Map<String, ConnectionPool> clusterNodes = ((JedisCluster) jedisClusterConnection.getNativeConnection()).getClusterNodes();
而 ConnectionPool 类中包裹的 Connection类 没有JedisPool类中包裹的 Jedis类的 info()方法和 scan()方法;
所以我们可以有两个解题思路:
1.使用Connection中的sendCommand 模拟 info()方法和 scan()方法(只是猜想、未实现);
2.如上文中自己构建 Jedis对象;
相关文章:
SpringBoot3 + Jedis5 + Redis集群 如何通过scan方法分页获取所有keys
背景: 由于需要升级老项目代码,从SpringBoot1.5.x 升级到 SpringBoot3.3.x,框架中引用的Jedis自动升级到了 5.x;正好代码中有需要获取Redis集群的所有keys的需求存在;代码就不适用了,修改如下: POM 由于…...
WGCLOUD监控系统部署教程
官网地址:下载WGCLOUD安装包 - WGCLOUD官网 第一步、环境配置 #安装jdk 1、安装 EPEL 仓库: sudo yum install -y epel-release 2、安装 OpenJDK 11: sudo yum install java-11-openjdk-devel 3、如果成功,你可以通过运行 java …...
协议-WebRTC-HLS
是什么? WebRTC(Web Real-Time Communication) 实现 Web 浏览器和移动应用程序之间通过互联网直接进行实时通信。允许点对点音频、视频和数据共享,而无需任何插件或其他软件。WebRTC 广泛用于构建视频会议、语音通话、直播、在线游…...
jQuery UI 下载指南
jQuery UI 下载指南 引言 jQuery UI 是一个基于 jQuery 的用户界面和交互库,它提供了一套丰富的交互组件和视觉效果,可以帮助开发者快速构建美观、交互性强的网页应用。本文将为您详细介绍如何下载 jQuery UI,并指导您进行安装和使用。 jQ…...
MySQL系列之数据类型(String)
导览 前言一、字符串类型知多少 1. 类型说明2. 字符和字节的转换 二、字符串类型的异同 1. CHAR & VARCHAR2. BINARY & VARBINARY3. BLOB & TEXT4. ENUM & SET 结语精彩回放 前言 MySQL数据类型第三弹闪亮登场,欢迎关注O。 本篇博主开始谈谈MySQ…...
Kotlin 2.1.0 入门教程(十)if、when
if 表达式 if 是一个表达式,它会返回一个值。 不存在三元运算符(condition ? then : else),因为 if 在这种场景下完全可以胜任。 var max aif (a < b) max bif (a > b) {max a } else {max b }max if (a > b) a…...
编程式路由
<script> export default {name: video-Info1,created () {setTimeout(() > {this.$router.push({ name: home })}, 3000)} } </script> 编程式路由:实现 不需要用户点击router-link,由代码实现路由跳转。 应用场景:用户登录…...
openAI官方prompt技巧(一)
1. 使用最新的模型 2. 将指令放在提示词的开头,并使用 ### 或 """ 来分隔指令和上下文,例如 错误示范❌ 将下面的文本总结为一个要点列表,列出最重要的内容。 Summarize the text below as a bullet point list of the most…...
利用 Python 爬虫获取按关键字搜索淘宝商品的完整指南
在电商数据分析和市场研究中,获取商品的详细信息是至关重要的一步。淘宝作为中国最大的电商平台之一,提供了丰富的商品数据。通过 Python 爬虫技术,我们可以高效地获取按关键字搜索的淘宝商品信息。本文将详细介绍如何利用 Python 爬虫技术获…...
LeetCode 0080.删除有序数组中的重复项 II:双指针 - C++/Java5 行版
【LetMeFly】80.删除有序数组中的重复项 II:双指针 - C/Java5 行版 力扣题目链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/ 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超…...
【C++高并发服务器WebServer】-15:poll、epoll详解及实现
本文目录 一、poll二、epoll2.1 相对poll和select的优点2.2 epoll的api2.3 epoll的demo实现2.5 epoll的工作模式 一、poll poll是对select的一个改进,我们先来看看select的缺点。 我们来看看poll的实现。 struct pollfd {int fd; /* 委托内核检测的文件描述符 */s…...
MapReduce是什么?
MapReduce 是一种编程模型,最初由 Google 提出,旨在处理大规模数据集。它是分布式计算的一个重要概念,通常用于处理海量数据并进行并行计算。MapReduce的基本思想是将计算任务分解为两个阶段:Map 阶段和 Reduce 阶段。 Map 阶段&a…...
git提交到GitHub问题汇总
1.main->master git默认主分支是maser,如果是按照这个分支名push,GitHub会出现两个branch,与预期不符 解决方案:更改原始主分支名为main git config --global init.defaultBranch main2.git:OpenSSL SSL_read: SS…...
CNN-GRU卷积神经网络门控循环单元多变量多步预测,光伏功率预测(Matlab完整源码和数据)
代码地址:CNN-GRU卷积神经网络门控循环单元多变量多步预测,光伏功率预测(Matlab完整源码和数据) CNN-GRU卷积神经网络门控循环单元多变量多步预测,光伏功率预测 一、引言 1.1、研究背景和意义 随着全球能源危机和环境问题的日…...
编译原理面试问答
编译原理面试拷打 1.编译原理的基本概念 编译原理是研究如何将高级程序语言转换为计算机可执行代码的理论与技术,其核心目标是实现高效、正确的代码翻译。 **编译器:**将源代码转化为目标代码(机器码、字节码等)。一次翻译整个程…...
LIMO:上海交大的工作 “少即是多” LLM 推理
25年2月来自上海交大、SII 和 GAIR 的论文“LIMO: Less is More for Reasoning”。 一个挑战是在大语言模型(LLM)中的复杂推理。虽然传统观点认为复杂的推理任务需要大量的训练数据(通常超过 100,000 个示例),但本文展…...
Java 魔法:精准掌控 PDF 合同模板,指定页码与关键字替换签章日期
朋友们!在实际业务场景中,经常会碰到处理 PDF 合同模板的需求,要在几十页的合同里对指定页面替换公章、签名和日期,还涉及多人签名以及多个公司盖公章。下面就给大家分享两种用 Java 处理这类问题的方法,一种是通过指定…...
Ollama 部署本地大语言模型
一、下载安装ollama 1.百度 ollama Ollama 2.点击下载 可以复制下载链接,使用下载器下载。 3.双击安装 默认安装目录:C:\Users\用户名\AppData\Local\Programs\Ollama 二、更改模型下载目录 0.默认下载目录 (跳过) 之前没下载过模型,不…...
Jackson扁平化处理对象
POJO对象 Data public class People {private PeopleInfo peopleInfo;private List<String> peopleIds;private Map<String, String> peopleMap;Datapublic static class PeopleInfo {private String name;private String address;} }JSON序列化处理 直接将对象进…...
在 Ubuntu 上安装 MySQL 的详细指南
在Ubuntu环境中安装 mysql-server 以及 MySQL 开发包(包括头文件和动态库文件),并处理最新版本MySQL初始自动生成的用户名和密码,可以通过官方的APT包管理器轻松完成。以下是详细的步骤指南,包括从官方仓库和MySQL官方…...
pytest-xdist 进行多进程并发测试!
在软件开发过程中,测试是确保代码质量和可靠性的关键步骤。随着项目规模的扩大和复杂性的增加,测试用例的执行效率变得尤为重要。为了加速测试过程,特别是对于一些可以并行执行的测试用 例,pytest-xdist 提供了一种强大的工具&…...
24.ppt:小李-图书策划方案【1】
目录 NO1234 NO5678 NO1234 新建PPT两种方式👇docx中视图→导航窗格→标题1/2/3ppt新建幻灯片→从大纲→重置开始→版式设计→主题插入→表格 NO5678 SmartArt演示方案:幻灯片放映→自定义幻灯片放映→新建→选中添加...
模型 替身决策
系列文章分享模型,了解更多👉 模型_思维模型目录。替身决策,换位思考,多角度决策。 1 替身决策模型的应用 1.1 替身决策模型在面试中的应用-小李的求职面试 小李是一名应届毕业生,正在积极寻找工作机会。在面试过程中…...
ESP32S3读取数字麦克风INMP441的音频数据
ESP32S3 与 INMP441 麦克风模块的集成通常涉及使用 I2S 接口进行数字音频数据的传输。INMP441 是一款高性能的数字麦克风,它通过 I2S 接口输出音频数据。在 Arduino 环境中,ESP32S3 的开发通常使用 ESP-IDF(Espressif IoT Development Framew…...
docker环境下部署face-search开源人脸识别模型
由于我们是直接将face-search部署在docker容器中的,所以,在部署之前一定要检查一下自己的docker环境,要不然部署过程中会出现各种各样的问题 我这里的docker环境是 一、安装docker环境 如果docker版本比较低或者docker-compose的版本比较低的情况下,部署的时候docker的yml…...
301.华为交换机堆叠技术基础
华为交换机堆叠技术基础 一、概念及原理部分1.堆叠简介1.1 什么是堆叠1.2 可靠性网络架构1.3 华为堆叠设备1.4 其他厂商的堆叠2.堆叠的示意图3.堆叠的应用3.1 中小企业3.2 园区网4.堆叠的原理4.1基本的概念4.2 堆叠建立4.3 角色选举4.4 版本同步4.5 配置同步4.6 堆叠系统的登录…...
【数据库创建】用ij工具部署Derby数据库并验证
Java有一个内置的Derby数据库,是一个完全用Java语言编写的、功能强大的微型数据库,其基础引擎和内嵌的JDBC驱动总共大约2MB大小。Derby为用户提供了轻量的标准数据库引擎,它可以紧密地嵌入到任何基于Java的解决方案中。 Derby的特性令人惊奇&…...
飞牛fnOS安装了Airplay没有声音找不到声卡的问题
主要问题描述:我在飞牛的Docker里安装了 Airplay, 这样把NAS接一个外接音箱,就可以当成无线音箱来用,直接把手机的音乐播放投到上面来播放。 (文章底部有写我是怎么安装Airplay的) 我的报错如下࿱…...
netcore openTelemetry+prometheus+grafana
一、netcore项目 二、openTelemetry 三、prometheus 四、grafana添加Dashborad aspire/src/Grafana/dashboards at main dotnet/aspire GitHub 导入:aspnetcore.json和aspnetcore-endpoint.json 效果:...
全程Kali linux---CTFshow misc入门(38-50)
第三十八题: ctfshow{48b722b570c603ef58cc0b83bbf7680d} 第三十九题: 37换成1,36换成0,就得到长度为287的二进制字符串,因为不能被8整除所以,考虑每7位转换一个字符,得到flag。 ctfshow{5281…...
