Springboot下使用Redis管道(pipeline)进行批量操作
之前有业务场景需要批量插入数据到Redis中,做的过程中也有一些感悟,因此记录下来,以防忘记。下面的内容会涉及到
分别使用for、管道处理批量操作,比较其所花费时间。
分别使用RedisCallback、SessionCallback进行Redis pipeline 操作
解释RedisCallback、SessionCallback这两种用法的区别
1.网络传输(RTT)开销少
Redis的传输层是基于TCP协议,一次操作请求的完成,存在网络传输来回的开销,即使Redis每秒能接受10万的请求,但也会因为网络传输而浪费很多时间,导致降低整体的性能。所以面对大量的批量处理,可以使用Redis的管道(pipeline),优势在于多次指令操作只会使用一次的网络传输的开销。
PS:像批量插入、批量获取,RedisTemplate提供了multiSet、multiGet的方法可以进行操作,不过像multiSet并不支持批量设置key的过期时间,可以考虑业务场景进行使用
2.提高redis每秒可以执行操作的数量
在进行批量操作的前提下
不使用管道的时候,每一次Redis执行命令,都要涉及到读(read)和写(write)的系统调用,系统会将用户端切换到内核端。上下文切换会有一定的消耗使用管道的话,多条命令只需要一个读(read),多条响应只需要一个写(write),可想而知,这其中省下了很多的消耗。
环境配置
JDK8
Spring boot 2.6.13
spring-boot-starter-data-redis
分别使用for、管道处理批量操作,比较其所花费时间
public void testForOrPipeline(){//使用forStopWatch stopWatch1=new StopWatch();stopWatch1.start();for(int i=0;i<10000;i++){String value = String.valueOf(i);String key = "test:" + value;redisTemplate.opsForValue().set(key, value, 10, TimeUnit.SECONDS);}stopWatch1.stop();System.out.println("for所需时间:"+stopWatch1.getTotalTimeSeconds()+"s");//使用管道StopWatch stopWatch2=new StopWatch();stopWatch2.start();List<Boolean> list = redisTemplate.executePipelined(new SessionCallback<Object>() {@Overridepublic Object execute(RedisOperations operations) throws DataAccessException {for (int i = 0; i < 10000; i++) {String value = String.valueOf(i);String key = "test:" + value;operations.opsForValue().set(key, value, 10, TimeUnit.SECONDS);}return null;}});stopWatch2.stop();System.out.println("管道所需时间:"+stopWatch2.getTotalTimeSeconds()+"s");
}

PS: 本地,且只有一个客户端的情况下测试(做不到严谨性,见谅)
目前只是本地跑(网络传输所带来的开销本身会很小),如果redis服务端是在其他地区的服务器上,这两种方式所需的时间相差还会越来越大。
RedisCallback
private void RedisCallBackHandler() {//这里获取String类型的序列化器RedisSerializer stringSerializer = redisTemplate.getStringSerializer();//第二个参数是指定结果反序列化器,用于反序列化管道中读到的数据,不是必传,//如果不传,则使用自定义RedisTemplate的配置,//如果没有自定义,则使用RedisTemplate默认的配置(JDK反序列化)List list = redisTemplate.executePipelined(new RedisCallback<Object>() {@Overridepublic Object doInRedis(RedisConnection connection) throws DataAccessException {for (int i = 0; i < 10; i++) {String value = String.valueOf(i);String key="test:"+value;connection.setEx(stringSerializer.serialize(key),10,stringSerializer.serialize(value));}//这里bytes只会获取到null,因为这里get操作只是放在管道里面,并没有//真正执行,所以获取不到值//byte[] bytes = connection.get("test:1".getBytes());connection.get("test:1".getBytes());//executePipelined 这个方法需要返回值为null,不然会抛异常,//这一点可以查看executePipelined源码return null;}}, stringSerializer);list.stream().forEach(result->{System.out.println(result);});
}
SessionCallback
private void SessionCallBackHandler() {//这里获取String类型的序列化RedisSerializer stringSerializer = redisTemplate.getStringSerializer();//第二个参数是指定结果反序列化器,用于反序列化管道中读到的数据,不是必传,//如果不传,则使用自定义RedisTemplate的配置,//如果没有自定义,则使用RedisTemplate默认的配置(JDK反序列化)List list = redisTemplate.executePipelined(new SessionCallback<Object>() {@Overridepublic Object execute(RedisOperations operations) throws DataAccessException {for (int i = 0; i < 10; i++) {String value = String.valueOf(i);String key = "test:" + value;operations.opsForValue().set(key, value, 10, TimeUnit.SECONDS);}//这里o只会获取到null,因为这里get操作只是放在管道里面,并没有真正执行,所以获取不到值//Object o = operations.opsForValue().get("test:1");operations.opsForValue().get("test:1");//executePipelined 这个方法需要返回值为null,不然会抛异常,//这一点可以查看executePipelined源码return null;}}, stringSerializer);list.stream().forEach(result->{System.out.println(result);});
}
解释RedisCallback、SessionCallback这两种用法的区别
上面代码显示了RedisCallback、SessionCallback这两种都能实现相同的效果,那么这两个又有什么区别呢?
SessionCallback 的使用比RedisCallback要友好一些
SessionCallback的execute方法提供给使用者使用的是RedisOperations接口类,RedisTemplate实现类
RedisCallback的doInRedis方法提供给使用者使用的是RedisConnection接口类,也就是LettuceConnection是实现类
RedisConnection提供了字节数组类型的get和set方法,有关序列化部分的细节还需要我们去关心。(和使用原生jdbc感受差不多),而RedisTemplate负责序列化和连接管理,不需要让使用者关系这一块的部分。总结: 个人感觉从日常使用上应该都倾向于SessionCallback,而个别特殊有关底层的业务,可能就需要RedisCallback。
相关文章:
Springboot下使用Redis管道(pipeline)进行批量操作
之前有业务场景需要批量插入数据到Redis中,做的过程中也有一些感悟,因此记录下来,以防忘记。下面的内容会涉及到 分别使用for、管道处理批量操作,比较其所花费时间。 分别使用RedisCallback、SessionCallback进行Redis pipeline …...
Vue技巧大揭秘:自定义指令的力量与应用
引言 自定义指令就像是给予开发者的一把魔法钥匙,它能够打开DOM操作的新世界,按我的理解就是把对DOM操作的逻辑进行封装 全局注册与局部注册 全局注册 定义: 全局注册意味着自定义指令在Vue实例创建之前通过Vue.directive()方法注册&…...
HR人才测评,如何考察想象力?
什么是想象力? 想象力是指,人们通过在已有物质的基础上,通过大脑想象、加工、创造出新事物的能力,举一个非常简单的例子,在提到鸟这种生活的时候,大家会联想到各种各样不同鸟的品种。 在企业招聘中常常应…...
Git命令远程分支的合并和本地分支的同步
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
墨烯的C语言技术栈-C语言基础-003
三.数据类型 1.char // 字符数据型 2.short // 短整型 3.int // 整型 4.long // 长整型 5.long long // 更长的整型 6.float // 单精度浮点数 7.double // 双精度浮点数 为什么写代码? 为了解决生活中的问题 购物,点餐,看电影 为什么有这么多类型呢? 因为说的话都是字符型…...
RpcRrovider分发rpc服务(OnMessage和Closure回调)
目录 1.完善rpcprovider.cc的OnConnection 2.完善rpcprovider.cc的OnMessage 3.完整rpcprovider.h 4.完整rpcprovider.cc 这篇文章主要完成,protobuf实现的数据序列化和反序列化。 1.完善rpcprovider.cc的OnConnection rpc的请求是短连接的,请求一次…...
分解+降维+预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测
分解降维预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测 目录 分解降维预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测效果一览基本介绍程序设计参…...
【Python】MacBook M系列芯片Anaconda下载Pytorch,并开发一个简单的数字识别代码(附带踩坑记录)
文章目录 配置镜像源下载Pytorch验证使用Pytorch进行数字识别 配置镜像源 Anaconda下载完毕之后,有两种方式下载pytorch,一种是用页面可视化的方式去下载,另一种方式就是直接用命令行工具去下载。 但是由于默认的Anaconda走的是外网&#x…...
自定义控件动画篇(四)ObjectAnimator的使用
ObjectAnimator 是 Android 属性动画框架中的一个重要组件,它允许你针对特定属性的值进行动画处理。与 ValueAnimator 相比,ObjectAnimator 更专注于 UI 组件,可以直接作用于视图的属性,如位置、尺寸、透明度等,而无需…...
实现List接口的ArrayList和LinkedList
package study;import java.util.*;public class day01_list {public static void main(String[] args) {// <Integer> 这个尖括号表示的是 Java 的泛型(Generics)// 泛型是 Java 5 引入的一项特性,它允许你在 类、接口和方法 中使用类…...
下拉选择输入框(基于elment-ui)
最近在需求中,需要有一个下拉选择功能,又得可以输入,在 element-ui 官网找了,发现没有适合的,然后在修炼 cv 大法的我,也在网上看了一下,但是也都感觉不合适,所以就自己写了两个&…...
CPP入门:日期类的构建
目录 1.日期类的成员 2.日期类的成员函数 2.1构造和析构函数 2.2检查日期合法 2.3日期的打印 2.4操作符重载 2.4.1小于号 2.4.2等于号 2.4.3小于等于号 2.4.4大于号 2.4.5大于等于号 2.4.6不等号 2.4.7加等的实现 2.4.8加的实现 2.4.9减去一个天数的减等实现 2.4.10…...
springboot学习,如何用redission实现分布式锁
目录 一、springboot框架介绍二、redission是什么三、什么是分布式锁四、如何用redission实现分布式锁 一、springboot框架介绍 Spring Boot是一个开源的Java框架,由Pivotal团队(现为VMware的一部分)于2013年推出。它旨在简化Spring应用程序…...
【MySQL】如果表被锁可以尝试看一下事务
今天在MySQL中删除表的时候,发现无法删除,一执行drop,navicat就卡死。 通过 SHOW PROCESSLIST显示被锁了 kill掉被锁的进程后依旧被锁 最后发现是由于存在为执行完的事务 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX; kill掉这些事务以…...
Datawhale - 角色要素提取竞赛
文章目录 赛题要求一、赛事背景二、赛事任务三、评审规则1.平台说明2.数据说明3.评估指标4.评测及排行 四、作品提交要求五、 运行BaselineStep1:下载相关库Step2:配置导入Step3:模型测试Step4:数据读取Step5:Prompt设…...
【Sql-驯化】sql中对时间的处理方法技巧总结
【Sql-驯化】sql中对时间的处理方法技巧总结 本次修炼方法请往下查看 🌈 欢迎莅临我的个人主页 👈这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合,智慧小天地! 🎇 免费获取相关内容文档关注:微信公众…...
TFD那智机器人仿真离线程序文本转换为现场机器人程序
TFD式样那智机器人离线程序通过Process Simulation、DELMIA等仿真软件为载体给机器人出离线,下载下来的文本程序,现场机器人一般是无法导入及识别出来的。那么就需要TFD on Desk TFD控制器来进行转换,才能导入现场机器人读取程序。 导入的文…...
贪心+后缀和,CF 1903C - Theofanis‘ Nightmare
一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1903C - Theofanis Nightmare 二、解题报告 1、思路分析 我们任意一种分组其实都是若干个后缀和相加 比如我们分成了三组,第一组的数被加了一次,第二组的数被加了两次,第…...
10分钟完成微信JSAPI支付对接过程-JAVA后端接口
引入架包 <dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-WxPay</artifactId><version>${ijapy.version}</version></dependency>配置类 package com.joolun.web.config;import org.springframework.b…...
如何寻找一个领域的顶级会议,并且判断这个会议的影响力?
如何寻找一个领域的顶级会议,并且判断这个会议的影响力? 会议之眼 快讯 很多同学都在问:学术会议不是期刊,即使被SCI检索,也无法查询影响因子。那么如何知道各个领域的顶级会议,并对各个会议有初步了解呢…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
