【Redis】list数据类型相关指令

目录

list简单介绍

列表类型是用来存储多个有序的字符串,如图所示,a、b、c、d、e 五个元素从左到右组成了一个有序的列表,列表中的每个字符串称为元素,一个列表最多可以存储 2^32 - 1 个元素。在 Redis 中,可以对列表两端插入(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。

列表类型的特点:

(1)列表中的元素是有序的,这意味着可以通过索引下标获取某个元素或者某个范围的元素列表,就像数组一样,这里的有序不是指顺序降序,而是顺序表一样按照插入顺序排列着,可以随机访问。

(2)区分获取和删除的区别,例如上图中的 lrem 1 b 是从列表中把从左数遇到的前 1 个 b 元素删除,这个操作会导致列表的长度从 5 变成 4;但是执行 lindex 4 只会获取元素,但列表长度是不会变化的。

(3)列表中的元素是允许重复的,因为其定位类似数组,不是哈希。

lpush

将一个或者多个元素从左侧放入(头插)到 list 中。

时间复杂度是O(1),且这个操作是头插,lpush 的 l 是 left 的意思,所以先插入的在最后面。lpush 的 key 如果不存在,那么会自动创建插入,如果存在,value 不是 list 也会报错。

lpushx

在 key 存在时,将一个或者多个元素从左侧放入(头插)到 list 中。不存在,直接返回。

可以看到,如果 lpushx 的 key 不存在,那么就会直接返回0,lpushx 会返回插入成功后的 list 元素数量。

rpush

将一个或者多个元素从右侧放入(尾插)到 list 中。

rpushx

在 key 存在时,将一个或者多个元素从右侧放入(尾插)到 list 中。

lrange

获取从 start 到 end 区间的所有元素,左闭右闭。

注意这里是左闭右闭,而且支持倒数下标,-1 表示倒数第一个,以此类推。

lpop

从 list 左侧取出元素(即头删)。

带参数的功能是 Redis 6.2 版本新加的,我们也可以不带,不带就是删一个,该指令会返回删除的元素的值。

rpop

从 list 右侧取出元素(即尾删)。

lindex

获取从左数第 index 位置的元素。

如果是非法下标,则返回 nil。注意这里的时间复杂度是O(N),这个比较反直觉,因为其并不是真的一块连续的空间,能像数组一样随机访问,还是需要遍历的。

linsert

在特定位置插入元素。

这个指令很类似我们静态数组的 [] 查找元素。注意这里是给定一个基准值,从左向右遍历,找到第一个基准值,根据 before(之前) | after(之后)进行插入。如果从头到尾都没有找到,就会返回 -1。该指令返回插入之后的 list 长度。

llen

获取 list 长度。

这里的 list 的长度是指 list 的元素数量。

blpop 和 brpop

blpop 和 brpop 是 lpop 和 rpop 的阻塞版本。他们有什么区别呢?

在列表中有元素的情况下,阻塞和非阻塞表现是一致的。但如果列表中没有元素,非阻塞版本会理解返回 nil,但阻塞版本会根据 timeout,阻塞一段时间,期间 Redis 可以执行其他命令,但要求执行该命令的客户端会表现为阻塞状态。

命令中如果设置了多个键,那么会从左向右进行遍历键,一旦有一个键对应的列表中可以弹出元素,命令立即返回。

如果多个客户端同时对一个键执行 pop,则最先执行命令的客户端会得到弹出的元素,也就是会根据先来后到排个队,因为之前也说过,Redis 可以用来作为消息队列,也就是生产消费者模型,早期 list 就可以用来做消息队列,这个机制可以用来防止消费者饥饿问题。


可以看到,第一次 blpop 时因为 list 为空所以阻塞了,插入元素后就弹出对应值返回了,还标明了操作时间,因为可以同时 blpop 多个 key,所以这里返回时还会表明哪个 key 的。如果一直没有元素,就会超时返回 nil。

lrem

从 list 中删除指定值的元素

该指令就是指定元素值和数量,然后删除对应数量的元素。但是该指令的 count 有以下规则:

count > 0:从表头到表尾遍历,删除前 count 个等于 value 的元素;

count < 0:从表尾到表头遍历,删除前 abs(count) 个等于 value 的元素;

count = 0:删除 List 中所有等于 value 的元素;

此外,如果 count 数量超过了 list 中实际存在的该元素数,不会报错,而是适应一下,该元素全部删除。

ltrim

修剪 List(裁剪列表) 的核心命令,简单说就是保留 List 中指定索引范围的元素,删除范围外的所有元素,常用来实现「固定长度的列表」(比如最近 N 条日志、消息队列长度限制)。

可以看到范围是左闭右闭的,且支持倒数,且可以适应参数。

编码方式

以前的列表类型的内部编码有两种:

ziplist(压缩列表):当列表的元素个数小于 list-max-ziplist-entries 配置(默认 512 个),同时列表中每个元素的长度都小于 list-max-ziplist-value 配置(默认 64 字节)时,Redis 会选用ziplist 来作为列表的内部编码实现来减少内存消耗。

linkedlist(链表):当列表类型无法满足 ziplist 的条件时,Redis 会使用 linkedlist 作为列表的内部实现。

但是现在被舍弃了,现在不管个数和长度,都是用的 quicklist,quicklist可以认为是 ziplist 和 linkedlist 的合体,整体是一个链表,但是节点是一个个压缩链表。

使用场景

Redis 列表类型的核心用途主要体现在两大场景:一是作为消息队列使用,利用 lpush+brpop 的命令组合实现阻塞式生产者 - 消费者模型,生产者通过 lpush 向列表插入消息,多个消费者借助 brpop 阻塞式争抢队列元素,既保证消费的负载均衡与高可用性,还能通过不同键名模拟分频道队列,让消费者针对性监听不同键实现消息分频道订阅;二是用于实现有序的时序类列表展示,典型如微博 Timeline 场景,将用户的微博标识存入专属列表,借助 lpush 维护最新在前的有序性,通过 lrange 按索引范围分页获取内容,满足分页展示需求,虽存在 1+n 查询、中间元素获取效率低等问题,但可通过 pipeline 批量操作、列表拆分等方式优化。

相关推荐
晚霞的不甘2 小时前
Flutter for OpenHarmony实现高性能流体粒子模拟:从物理引擎到交互式可视化
前端·数据库·经验分享·flutter·microsoft·计算机视觉
Access开发易登软件2 小时前
Access 中实现 Web 风格的顶部加载进度条
前端·数据库·vba·access·access开发
野犬寒鸦2 小时前
从零起步学习并发编程 || 第二章:多线程与死锁在项目中的应用示例
java·开发语言·数据库·后端·学习
定偶2 小时前
事务、触发器、存储过程与视图全解析
数据库·oracle
范纹杉想快点毕业2 小时前
STM32单片机与ZYNQ PS端 中断+状态机+FIFO 综合应用实战文档(初学者版)
linux·数据结构·数据库·算法·mongodb
拓云者也2 小时前
常用的生物信息学数据库以及处理工具
数据库·python·oracle·r语言·bash
Henry Zhu1232 小时前
数据库(二):数据模型
数据库
曹牧2 小时前
Java:将字符串转换为整数
java·数据库
hcnaisd22 小时前
机器学习模型部署:将模型转化为Web API
jvm·数据库·python