【Redis】深入探索 Redis 的数据类型 —— 列表 List
文章目录
- 一、List 类型介绍
- 二、List 类型相关命令
- 2.1 LPUSH 和 RPUSH、LPUSHX 和 RPUSHX
- 2.2 LPOP 和 RPOP、BLPOP 和 BRPOP
- 2.3 LRANGE、LINDEX、LINSERT、LLEN
- 2.4 列表相关命令总结
- 三、List 类型内部编码
- 3.1 压缩列表(ziplist)
- 3.2 链表(linkedlist)
- 四、List 类型的应用场景
- 4.1 消息队列
- 4.2 微博列表
一、List 类型介绍
list 列表类型是用来存储多个有序的字符串,列表中的每个字符串称为元素(element),一个列表最多可以存储 2^32 - 1 个元素。在 Redis 中,可以对列表两端插人(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是⼀种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。
列表两端插入和弹出操作:
列表的获取、删除等操作:
列表类型的特点:
- 列表中的元素是有序的,这意味着可以通过索引下标获取某个元素或者某个范围的元素列表;
- 区分获取和删除的区别,例上图 中的
lrem 1 b
是从列表中把从左数遇到的前 1 个 b 元素删除,这个操作会导致列表的长度从 5 变成 4;但是执行lindex 4
只会获取元素,但列表长度不会变化。 - 列表中的元素是允许重复的,例如下图中的列表中是包含了两个 a 元素的。
二、List 类型相关命令
2.1 LPUSH 和 RPUSH、LPUSHX 和 RPUSHX
LPUSH
和RPUSH
LPUSH
命令的作用是将一个或多个元素从左侧(头插)插入到 list 中;而 RPUSH
命令的作用则是将一个或多个元素从右侧(尾插)插入到 list 中。
语法:
LPUSH key element [element ...]RPUSH key element [element ...]
LPUSHX
和RPUSHX
LPUSHX
命令的作用是当 key 存在时,将⼀个或者多个元素从左侧放⼊(头插)到 list 中,不存在则直接返回;而 RPUSHX
命令的作用是是当 key 存在时,将⼀个或者多个元素从右侧放⼊(头插)到 list 中,不存在则直接返回。
语法:
LPUSHX key element [element ...]RPUSHX key element [element ...]
2.2 LPOP 和 RPOP、BLPOP 和 BRPOP
LPOP
和RPOP
LPOP
命令的作用是从左侧删除一个元素(头删),并返回删除的值;而 RPOP
则是从右侧删除(尾删),然后返回删除的值。
语法:
LPOP keyRPOP key
BLPOP
和BRPOP
BLPOP
和 BRPOP
命令的作用和LPOP
、 RPOP
一样,只是需要指定一个超时时间,如果没有元素可以删除的时候,会进行阻塞,如果在设定的超时时间内向 Redis 中插入元素,则会立即执行;否则超时则之间退出。
语法:
BLPOP key [key ...] timeoutBRPOP key [key ...] timeout
另外,BLPOP
和 BRPOP
可以同时指定多个 key 进行删除。
2.3 LRANGE、LINDEX、LINSERT、LLEN
LRANGE
LRANGE
命令的作用是获取从 start 到 stop 区间的所有元素,区间左闭右闭,并且指定的位置可以是负数,表示倒数第几个。
语法:
LRANGE key start stop
LINDEX
LINDEX
命令的作用是获取从左边开始第 index 位置的元素。
语法:
LINDEX key index
LINSERT
LINSERT
命令的作用是在特定的位置插入元素。
语法:
LINSERT key BEFORE|AFTER pivot element
说明:
BEFORE
表示插入到 pivot 元素之前;AFTER
表示插入到 pivot 元素之后。
LLEN
LLEN
命令的作用是 获取 list 长度。
语法:
LLEN key
2.4 列表相关命令总结
以下是关于 Redis List 相关命令的总结,包括命令、作用以及时间复杂度:
命令 | 作用 | 时间复杂度 |
---|---|---|
LPUSH | 从列表左侧插入一个或多个元素 | O(N) (N 为插入元素数量) |
RPUSH | 从列表右侧插入一个或多个元素 | O(N) (N 为插入元素数量) |
LPUSHX | 如果列表存在,从左侧插入一个或多个元素,否则不执行操作 | O(1) |
RPUSHX | 如果列表存在,从右侧插入一个或多个元素,否则不执行操作 | O(1) |
LPOP | 从列表左侧删除并返回一个元素 | O(1) |
RPOP | 从列表右侧删除并返回一个元素 | O(1) |
BLPOP | 从左侧删除并返回元素,如果列表为空则阻塞,带有超时参数 | O(1) 或阻塞等待 |
BRPOP | 从右侧删除并返回元素,如果列表为空则阻塞,带有超时参数 | O(1) 或阻塞等待 |
LRANGE | 获取指定范围内的元素列表 | O(Slice Size) |
LINDEX | 获取指定位置的元素 | O(N) (N 为索引位置) |
LINSERT | 在指定元素前或后插入新元素 | O(N) (N 为列表长度) |
LLEN | 获取列表的长度 | O(1) |
注意:时间复杂度中的 “N” 表示操作的复杂度与列表的长度或插入元素的数量成线性关系,而不是固定的常数时间。在实际使用中,需要根据数据规模和性能要求选择适当的命令。
三、List 类型内部编码
Redis 中的 List 数据类型在内部可以使用不同的编码方式来存储数据,具体的编码方式取决于列表的大小和元素的大小。下面将介绍两种常见的 List 内部编码方式:
3.1 压缩列表(ziplist)
压缩列表(ziplist)是 Redis 中一种紧凑的、内存优化的列表编码方式,适用于存储较小的列表,或者列表中的元素都是较小的整数或字符串。压缩列表以连续的内存块的形式存储数据,每个节点可以包含一个或多个元素,这使得压缩列表在内存使用效率上有一定优势。
特点:
- 压缩列表可以保存多个元素在一个节点中,因此在元素较小的情况下,它可以节省内存。
- 压缩列表支持快速的元素访问,因为可以通过索引直接访问元素。
- 压缩列表适用于列表较小且元素较小的情况。
3.2 链表(linkedlist)
链表(linkedlist)是 Redis 中另一种列表的内部编码方式,它更适合存储大型列表或者元素大小不一致的列表。链表中的每个节点包含一个元素以及指向前一个节点和后一个节点的指针,这种结构使得链表在插入和删除元素时具有较高的效率。
特点:
- 链表适用于列表较大或元素较大的情况,因为它不需要连续的内存块,可以更好地处理大型数据。
- 链表对于插入和删除元素的操作更加高效,因为只需要调整节点的指针而不需要移动大量数据。
- 链表相对于压缩列表占用更多的内存,因为需要额外的指针来维护节点之间的链接。
总之,Redis 根据列表的大小和元素的大小自动选择使用压缩列表或链表来进行编码,以平衡内存使用和操作效率。在选择数据结构和命令时,需要考虑数据的规模和操作的性能需求。
示例:
1)当元素个数较少且没有大元素时,内部编码为 ziplist:
127.0.0.1:6379> rpush listkey e1 e2 e3
OK
127.0.0.1:6379> object encoding listkey
"ziplist"
2)当元素个数超过 512 时,内部编码为 linkedlist:
127.0.0.1:6379> rpush listkey e1 e2 e3 ... 省略 e512 e513
OK
127.0.0.1:6379> object encoding listkey
"linkedlist"
3)当某个元素的长度超过 64 字节时,内部编码为 linkedlist:
127.0.0.1:6379> rpush listkey "one string is bigger than 64 bytes ... 省略 ..."
OK
127.0.0.1:6379> object encoding listkey
"linkedlist"
四、List 类型的应用场景
4.1 消息队列
Redis 可以使用 lpush + brpop
命令组合实现经典的阻塞式生产者-消费者模型队列
,生产者客户端使用 lpush
从列表左侧插入元素,多个消费者客户端使用 brpop
命令阻塞式地从队列中 “争抢” 队首元素。通过多个客户端来保证消费的负载均衡和高可用性。
Redis 阻塞消息队列模型:
分频道的消息队列:
Redis 可以同样使用 lpush + brpop
命令,但通过不同的键模拟频道的概念,不同的消费者可以通过 brpop
不同的键值,实现订阅不同频道的理念。
4.2 微博列表
每个用户都有属于自己的微博列表 ,现需要分页展示文章列表。此时可以考虑使用列表类型,因为列表不但是有序的,同时支持按照索引范围获取元素。
1)每篇微博使用哈希结构存储,例如微博中 3 个属性:title、timestamp、content:
hmset mblog:1 title xx timestamp 1476536196 content xxxxx
...
hmset mblog:n title xx timestamp 1476536196 content xxxxx
2)向用户 的微博列表中添加微博,使用 user:<uid>:mblogs
作为微博的键:
lpush user:1:mblogs mblog:1 mblog:3
...
lpush user:k:mblogs mblog:9
3)分页获取用户的微博列表,例如获取用户1 的前 10 篇微博:
keylist = lrange user:1:mblogs 0 9
for key in keylist {hgetall key
}
此外,此方案在实际中可能存在两个问题:
- 1 + n 问题。即如果每次分页获取的微博个数较多,需要执行多次
hgetall
操作,此时可以考虑使用pipeline
(流水线)模式批量提交命令,或者微博不采用哈希类型,而是使用序列化的字符串类型,使用 mget 获取。 - 分页获取文章时,
lrange
在列表两端表现较好,获取列表中间的元素表现较差,此时可以考虑将列表做拆分。
相关文章:

【Redis】深入探索 Redis 的数据类型 —— 列表 List
文章目录 一、List 类型介绍二、List 类型相关命令2.1 LPUSH 和 RPUSH、LPUSHX 和 RPUSHX2.2 LPOP 和 RPOP、BLPOP 和 BRPOP2.3 LRANGE、LINDEX、LINSERT、LLEN2.4 列表相关命令总结 三、List 类型内部编码3.1 压缩列表(ziplist)3.2 链表(lin…...
高精度乘除法(超详细)
高精度乘除法(超详细) 题目1-高精度乘法 给定两个非负整数(不含前导 0) A 和 B,请你计算 AB 的值。 输入格式 共两行,第一行包含整数 A,第二行包含整数 B。 输出格式 共一行,包含…...
List 获取前N条数据
1.使用for循环遍历 public static void main(String[] args) {int limit 5;List<Integer> oldList Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);List<Integer> newList Lists.newArrayList();if (oldList.size() < limit) {newList.addAll(oldList);return;}fo…...
Spring入门控制反转(或依赖注入)AOP的关键概念 多配置文件与web集成
目录 1. 什么是spring,它能够做什么? 2. 什么是控制反转(或依赖注入) 3. AOP的关键概念 4. 示例 4.1 创建工程 4.2 pom文件 4.3 spring配置文件 4.4 示例代码 4.4.1 示例1 4.4.2 示例2 (abstract,parent示例) 4.4.3 使…...
排序算法-希尔排序
属性 1. 希尔排序是对直接插入排序的优化。 2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap 1时,数组已经接近有序的了,这样就会很 快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。 3.…...

ClientDataSet运行中出现“ClientDataSet:dataset not in edit or insert mode”(一)
在打开数据表文件,对ClientDataSet执行Append或Insert时,“ClientDataSet:dataset not in edit or insert mode”: 一、搜索问题 1、执行“显示数据后”,再执行Append,出错,说明ClientDataSet处…...

华为GaussDB数据库
Gauss数据库初识_高斯数据库_ygpGoogle的博客-CSDN博客 Redhat 7.6安装GaussDB_100_1.0.1详细攻略_gaussdb_100_1.0.1-database-redhat-64bit.tar.gz dow_博德1999的博客-CSDN博客 https://www.ngui.cc/el/3381579.html?actiononClick 初识GaussDB——GaussDB的发展历程、部…...

Flink、Spark、Hive集成Hudi
环境描述: hudi版本:0.13.1 flink版本:flink-1.15.2 spark版本:3.3.2 Hive版本:3.1.3 Hadoop版本:3.3.4 一.Flink集成Hive 1.拷贝hadoop包到Flink lib目录 hadoop-client-api-3.3.4.jar hadoop-client-runtime-3.3.4.jar 2.下载上传flink-hive的jar包 flink-co…...
百度编辑器 Ueditor 视频上传时 目录创建失败 解决办法
找到百度编辑器的上传类 Uploader.class.php文件.大约111左右 //$this->stateInfo $this->getStateInfo("ERROR_CREATE_DIR");//这句注释掉 $this->stateInfo $dirname;//换成这一句然后,进编辑器上传.会提示出一个错误的文件保存路径 双击复制下来这个路…...
Go 字符串处理
一、 字符串处理函数 我们从文件中将数据读取出来以后,很多情况下并不是直接将数据打印出来,而是要做相应的处理。例如:去掉空格等一些特殊的符号,对一些内容进行替换等。 这里就涉及到对一些字符串的处理。在对字符串进行处理时…...

家政服务接单小程序开发源码 家政保洁上门服务小程序源码 开源完整版
分享一个家政服务接单小程序开发源码,家政保洁上门服务小程序源码,一整套完整源码开源,可二开,含完整的前端后端和详细的安装部署教程,让你轻松搭建家政类的小程序。家政服务接单小程序开发源码为家政服务行业带来了诸…...

SuperMap iClient3D 11i (2023) SP1 for Cesium之移动实体对象
作者:nannan 目录 前言 一、代码思路 1.1 绘制面实体对象 1.2 鼠标左键按下事件 1.3 鼠标移动事件 1.4 鼠标左键抬起事件 二、运行效果 三、注意事项 前言 SuperMap 官网三维前端范例 编辑线面,可以对面实体对象的节点进行增加、删除以及修改位置…...

【深度学习 AIGC】stablediffusion-infinity 在无界限画布中输出绘画 Outpainting
代码:https://github.com/lkwq007/stablediffusion-infinity/tree/master 启动环境: git clone --recurse-submodules https://github.com/lkwq007/stablediffusion-infinity cd stablediffusion-infinity conda env create -f environment.yml conda …...

Flutter插件之阿里百川
上一篇:Flutter插件的制作和发布,我们已经了解了如何制作一个通用的双端插件,本篇就带领大家将阿里百川双端sdk制作成一个flutter插件供项目调用! 目录 登录并打开控制台,创建应用:填写应用相关信息开通百川…...

✔ ★ 算法基础笔记(Acwing)(三)—— 搜索与图论(17道题)【java版本】
搜索与图论 1. DFS1. 排列数字(3分钟)2. n-皇后问题 2. BFS(队列)1. 走迷宫二刷总结(队列存储一个节点pair<int,int>)三刷总结 走过的点标记上距离(既可以记录距离,也可以判断是否走过) ★ ★ 例题2. 八数码二刷…...

初试占比70%,计算机招生近200人,安徽理工大学考情分析
安徽理工大学 考研难度(☆) 内容:23考情概况(拟录取和复试分析)、院校概况、23专业目录、23复试详情、各专业考情分析、各科目考情分析。 正文980字,预计阅读:3分钟 2023考情概况 安徽理工大…...
LeetCode题解:1720. 解码异或后的数组,异或,JavaScript,详细注释
原题链接: https://leetcode.cn/problems/decode-xored-array/ 解题思路: 异或有如下性质: a ^ a 0a ^ 0 aa ^ b b ^ a 根据题意,已知encoded[i - 1] arr[i - 1] ^ arr[i],可以做如下转换: encoded[i…...

【C刷题】day2
一、选择题 1、以下程序段的输出结果是( ) #include<stdio.h> int main() { char s[] "\\123456\123456\t"; printf("%d\n", strlen(s)); return 0; } A: 12 B: 13 C: 16 D: 以上都不对【答案】: A 【解析】…...

Apollo源码安装的问题及解决方法
问题一 在进行git clone时,会报错Failed to connect to github.com port 443: Timed out,经过实践后推荐以下两种方法。 方法一:在原地址前加https://ghproxy.com 原地址:git clone https://github.com/ApolloAuto/apollo.git …...
Flutter 挖孔屏的状态栏占用问题怎么解决,横屏后去掉了状态栏,还是会有一块黑色的竖条
使用下方代码后依旧有一条黑色的区域 overridevoid initState() {// TODO: implement initStatesuper.initState();///关闭状态栏,与底部虚拟操作按钮SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);//隐藏状态栏,底部按钮栏S…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
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"…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...

Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...