目录
List列表
列表类型是⽤来存储多个有序的字符串,如图下图所示a、b、c、d、e 五个元素从左到右组成了⼀个有序的列表,列表中的每个字符串称为元素(element),⼀个列表最多可以存储个元素。在 Redis 中,可以对列表两端插⼊(push)和弹出(pop),还可以获取指定范围的元列表、获取指定索引下标的元素等。列表是⼀种⽐较灵活的数据结构,它可以充当栈和队列的⻆⾊,在实际开发上有很多应⽤场景。
列表类型的特点:
- 列表中的元素是有序的,这意味着可以通过索引下标获取某个元素或者某个范围的元素列表
- 区分获取和删除的区别
- 列表中的元素是允许重复的
命令
LPUSH
将一个或者多个元素从左侧放入(头插)到list中。
语法:
LPUSH key element [element ...]
**时间复杂度:**只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
**返回值:**插⼊后 list 的⻓度。
⽰例:
LPUSHX
在 key 存在时,将⼀个或者多个元素从左侧放⼊(头插)到 list 中。不存在,直接返回
语法:
LPUSHX key element [element ...]
**时间复杂度:**只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
**返回值:**插⼊后 list 的⻓度。
⽰例:
RPUSH
将⼀个或者多个元素从右侧放⼊(尾插)到 list 中。
语法:
RPUSH key element [element ...]
**时间复杂度:**只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
**返回值:**插⼊后 list 的⻓度。
⽰例:
RPUSHX
在 key 存在时,将⼀个或者多个元素从右侧放⼊(尾插)到 list 中。
语法:
RPUSHX key element [element ...]
**时间复杂度:**只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
**返回值:**插⼊后 list 的⻓度。
⽰例:
LRANGE
获取从 start 到 end 区间的所有元素,左闭右闭。
语法:
LRANGE key start stop
**时间复杂度:**O(N)
**返回值:**指定区间的元素。
⽰例:
说明:
- 在C++中,下标超出范围,一般认为这是一个"未定义行为";可能会导致程序崩溃,也可能会得到一个不合法的数据,还可能会得到一个看起来合法但是是错误的数据,也有可能恰好的到一个符合要求的数据;缺点:程序员不一定在第一时间发现问题;优点:效率非常高
- 在Java中,下标超出范围,一般会抛出异常,多出一步合法下标的验证 缺点:效率或者速度相比C++比较慢 优点:出现问题能够及时发现
- 在Redis中并没有采用上述两种设定,Redis的做法是直接尽可能的获取到给定区间的元素,如果区间非法,比如超出下标就会尽可能的获取对应的内容
LPOP
从 list 左侧取出元素(即头删)。
语法:
LPOP key
**时间复杂度:**O(1)
**返回值:**取出的元素或者 nil。
⽰例:
RPOP
从 list 右侧取出元素(即尾删)。
语法:
RPOP key
**时间复杂度:**O(1)
**返回值:**取出的元素或者 nil。
⽰例:
LINDEX
获取从左数第 index 位置的元素。
语法:
LINDEX key index
**时间复杂度:**O(N)
**返回值:**取出的元素或者 nil。
⽰例:
**说明:**并没有RINDEX命令,如果我们想从左边开始获取元素,可以让index设置为负数;
LINSERT
在特定位置插⼊元素。
语法:
LINSERT key <BEFORE | AFTER> pivot element
**时间复杂度:**O(N)
**返回值:**插⼊后的 list ⻓度。
⽰例:
LLEN
获取 list ⻓度。
语法:
LLEN key
**时间复杂度:**O(1)
**返回值:**list 的⻓度。
⽰例:
lrem
删除指定个数的指定元素
语法:
LERM key count element
**时间复杂度:**O(K)
**返回值:**删除元素的个数
示例:
说明:
- 当count>0时,从list的左边开始删除
- 当count<0时,从list的右边开始删除
- 当count=0时,删除 list中的所有元素
ltrim
保留start和stop之间区间的内的元素(区间外面两边的元素就直接被删除了)
语法:
LTRIM key start stop
时间复杂度:O(K)
**返回值:**执行成功返回OK
示例:
lset
根据下标修改元素
语法:
LSET key index element
**时间复杂度:**O(N)
**返回值:**执行成功返回OK
示例:
阻塞版本命令
blpop 和 brpop 是 lpop 和 rpop 的阻塞版本,和对应⾮阻塞版本的作⽤基本⼀致,除了:
- 在列表中有元素的情况下,阻塞和⾮阻塞表现是⼀致的。但如果列表中没有元素,⾮阻塞版本会理解返回 nil,但阻塞版本会根据 timeout,阻塞⼀段时间,期间 Redis 可以执⾏其他命令,但要求执⾏该命令的客⼾端会表现为阻塞状态。
- 命令中如果设置了多个键,那么会从左向右进⾏遍历键,⼀旦有⼀个键对应的列表中可以弹出元素,命令⽴即返回。
- 如果多个客⼾端同时多⼀个键执⾏ pop,则最先执⾏命令的客⼾端会得到弹出的元素。
BLPOP
LPOP的阻塞版本
语法:
BLPOP key [key ...] timeout
时间复杂度:O(1)
**返回值:**取出的元素或者 nil。
示例:
BRPOP
RPOP的阻塞版本
语法:
BRPOP key [key ...] timeout
**时间复杂度:**O(1)
**返回值:**取出的元素或者 nil。
**示例:**和上面BLPOP的用法相似就不演示了
内部编码
在Redis 5版本中,List的内部编码主要是quicklist。quicklist是Redis 3.2版本引入的一种新的数据结构,它是ziplist和linkedlist的结合体,旨在更好地平衡内存使用和访问速度。
quicklist通过维护一个双向链表,链表的每个节点都是一个ziplist。这种设计使得quicklist既能够像ziplist一样节省内存(因为ziplist会将多个元素压缩存储在一起),又能够像linkedlist一样快速地在两端进行插入和删除操作(因为linkedlist的双向特性)。
使用场景
消息队列
如下图所⽰,Redis 可以使⽤ lpush + brpop 命令组合实现经典的阻塞式⽣产者-消费者模型队列,⽣产者客⼾端使⽤ lpush 从列表左侧插⼊元素,多个消费者客⼾端使⽤ brpop 命令阻塞式地从队列中"争抢" 队⾸元素。通过多个客⼾端来保证消费的负载均衡和⾼可⽤性。
Redis阻塞消息队列模型
分频道的消息队列
如下图所⽰,Redis 同样使⽤ lpush + brpop 命令,但通过不同的键模拟频道的概念,不同的消费者可以通过 brpop 不同的键值,实现订阅不同频道的理念。
Redis分频道阻塞消息队列模型
作为栈或者队列
选择列表类型时,请参考:
同侧存取(lpush + lpop 或者 rpush + rpop)为栈
异侧存取(lpush + rpop 或者 rpush + lpop)为队列
今天对Resid中list列表类型的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!!