Redis 的命令详解 - List 篇

LPUSH : 左端推入元素

起始版本 : 1.0.0
时间复杂度 : 添加一个元素为O(1),添加多个元素为O(N),N为要添加的元素个数。

将所有指定的值插入到存于 key 的列表的左端。如果 key 不存在,则在操作执行之前将其创建为空列表。如果key对应的value不是 list 类型时,则返回错误。

推入多个元素时,多个元素从左到右依次推入左端。例如,LPUSH mylist a b c 先推入a,结果为a。在推入b,结果为ba。最后推入c,结果为cba

语法

LPUSH key 元素1 [元素2 ...]

返回值

推入元素后列表的长度

历史

redis 版本 >= 2.4时,可接受多个element参数。在低于2.4的Redis版本中,只能接受一个element参数

LPUSHX : key 存在时,左端推入元素

起始版本 : 2.2.0
时间复杂度 : 添加一个元素为O(1),添加多个元素为O(N),N为要添加的元素个数。

只有当 key 存在,并且对应的 value 是 list 类型的时候,才执行操作。

语法

LPUSHX key 元素1 [元素2 ...]

返回值

推入元素后列表的长度

历史

redis 版本 >= 4.0时,可接受多个element参数。在低于4.0的Redis版本中,只能接受一个element参数。

RPUSH : 右端推入元素

起始版本 : 1.0.0
时间复杂度 : 添加一个元素为O(1),添加多个元素为O(N),N为要添加的元素个数。

将所有指定的值插入到存于 key 的列表的右端。如果 key 不存在,则在操作执行之前将其创建为空列表。如果key对应的value不是 list 类型时,则返回错误。

推入多个元素时,多个元素从左到右依次推入右端。例如,RPUSH mylist a b c 先推入a,结果为a。在推入b,结果为ba。最后推入c,结果为cba

语法

RPUSH key 元素1 [元素2 ...]

返回值

推入元素后列表的长度

历史

redis 版本 >= 2.4时,可接受多个element参数。在低于2.4的Redis版本中,只能接受一个element参数

RPUSHX : key 存在时,右端推入元素

起始版本 : 2.2.0
时间复杂度 : 添加一个元素为O(1),添加多个元素为O(N),N为要添加的元素个数。

只有当 key 存在,并且对应的 value 是 list 类型的时候,才执行操作。

语法

RPUSHX key 元素1 [元素2 ...]

返回值

推入元素后列表的长度

历史

redis 版本 >= 4.0时,可接受多个element参数。在低于4.0的Redis版本中,只能接受一个element参数。

LPOP : 左端弹出

起始版本 : 1.0.0
时间复杂度 : O(1)

删除(弹出)最左端的元素

当list中没有元素时(比如元素都被弹出),key 会被删除

语法

LPOP key

返回值

弹出元素的值,当key不存在时,返回nil

RPOP : 右端弹出

起始版本 : 1.0.0
时间复杂度 : O(1)

删除(弹出)最右端的元素

当list中没有元素时(比如元素都被弹出),key 会被删除

语法

RPOP key

返回值

弹出元素的值,当key不存在时,返回nil,当list中没有元素时,返回null

LINDEX : 返回索引处的元素

起始版本 : 1.0.0
时间复杂度 : O(N),其中N是要遍历才能到达索引处元素的元素数。

索引从0开始,支持负索引,-1末尾最后一个元素

语法

LINDEX key index

返回值

索引处的元素,索引越界,返回null

LINSERT : 在目标元素前或后插入元素

起始版本 : 2.2.0
时间复杂度 : O(N),其中N是要遍历才能到达插入点的元素数量,这意味着最左端的元素为O(1)

list 存在多个相同的目标元素时,从左往右选择第一个。

语法

LINSERT key BEFORE|AFTER 目标元素 value

目标元素为 value 的插入点,BEFORE、AFTER 指定在目标元素的前后插入

返回值

插入操作后的list长度,当目标元素找不到时,返回 -1。

LRANGE : 获取指定范围的元素

起始版本 : 1.0.0
时间复杂度 : O(S + N) 其中 S 是小列表到 HEAD 的起始偏移量,大列表到最近的头 (HEAD或TAIL) 的起始偏移量,N 是指定范围内的元素数。

范围获取元素,下标从0开始,支持负下标,-1表示最右端的元素,包括开始下标,也包括结束下标

索引越界

超出范围的索引不会产生错误。

如果开始下标大于列表的末尾,则返回一个空列表。

如果结束下标大于列表的实际末尾,则Redis会将其视为列表的最后一个元素。

命令

LRANGE key 开始下标 结束下标

返回值

范围内的元素列表

LLEN : 获取list的长度

起始版本 : 2.2.0
时间复杂度 : O(1)

语法

LLEN key

返回值

  • list 的长度 : 正常返回时
  • 0 : key不存在
  • 错误 : key 对应的 value 不是 list 类型

LREM : 删除n个指定元素

起始版本 : 2.2.0
时间复杂度 : O(N+M),其中N是列表的长度,M是删除的元素数。

从列表中删除 count 个 value 元素。

  • count > 0: 从头往尾移除指定元素。
  • count < 0: 从尾往头移除指定元素。
  • count = 0: 移除列表所有的指定元素。

比如, LREM list -2 “hello” 会从存于 list 的列表里移除最后两个出现的 “hello”。

需要注意的是,如果list里没有存在key就会被当作空list处理,所以当 key 不存在的时候,这个命令会返回 0。

语法

LREM key count 元素

返回值

已删除元素的数量。

LSET : 更新指定下标的值

起始版本 : 1.0.0
时间复杂度 : O(N),其中N是列表的长度。将列表的第一个或最后一个元素设置为O(1)。

更新指定下标的值, 当index超出范围时会返回一个error。

下标从0开始,支持负下标,-1表示最右端的元素

语法

LSET key index 新值

返回值

ok

LTRIM : 裁剪 list

起始版本 : 1.0.0
时间复杂度 : O(N),其中N是要由操作删除的元素数。

下标从0开始,支持负下标,-1表示最右端的元素,包括开始下标,也包括结束下标

例如有一个 list [01234]
LTRIM list 1 -2 的结果为 [123]

超出范围的索引不会产生错误:如果开始下标大于列表的末尾或 开始下标大于结束下标,结果将是一个空列表(空列表将导致key被删除)。

如果 结束下标 大于列表的末尾,则Redis会将其视为列表的最后一个元素。

LTRIM与LPUSH / RPUSH共同使用。例如:

语法

LTRIM key 开始下标 结束下标

返回值

ok

RPOPLPUSH : 右边弹出,左边推入

就想它的名称一样 R POP L PUSH,作用是将第一个 list 的最右端元素弹出,推入到 第二list的最左端,这个操作是原子行的。

我们称弹出元素的 list 为源list,推入元素的 list 为目标list

如果 源list 不存在,那么会返回 nil 值,并且不会执行任何操作。

如果 源list目标list 存在,那么这个操作等同于移除列表最后一个元素并且把该元素放在列表头部, 所以这个命令也可以当作是一个旋转列表的命令。

语法

RPOPLPUSH 源list 目标list

返回值

弹出的元素

BRPOPLPUSH : (阻塞式)右边弹出,左边推入

BRPOPLPUSHRPOPLPUSH的阻塞版。

源list 存在元素时,此命令的行为与RPOPLPUSH完全相同。

在MULTI / EXEC块中使用时,此命令的行为与RPOPLPUSH完全相同。

源list 为空时,Redis 将阻止连接,直到另一个客户端将元素推入源list或超时到达为止。

有关更多信息,请参见RPOPLPUSH。

语法

BRPOPLPUSH 源list 目标list timeout

timeout 是发生阻塞时的超时时间,单位秒。如果想一种阻塞下去,需要设置为 0。

返回值

弹出的元素,如果超时,返回null

BLPOP : 左端弹出(阻塞式)

起始版本 : 2.0.0
时间复杂度 : O(1)

(阻塞式)删除(弹出)最左端的元素

BLPOPLPOP 的阻塞版本。
两者区别

  • LPOP :key 对应的 value 中没有元素时,返回 null
  • BLPOP :key 对应的 value 中没有元素时,一直阻塞,直到 value 中有元素或超时。

除了上面的区别以外, BLPOP 命令还支持了多个 key。 当给定多个 key 时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的最左端元素。

语法

BLPOP key1 [key2] timeout

timeout 是发生阻塞时的超时时间,单位秒。如果想一种阻塞下去,需要设置为 0。

返回值

  • nil : 直到超时也没有弹出元素
  • 弹出元素的key : 弹出元素的值

非阻塞场景

BLPOP 命令不是所有情况下都会被阻塞

只要指定的 key 列表中有一个不为null,就不会被阻塞,而是返回该key和弹出的元素。如果有多个 key 都不为 null,依次从做往右,找到第一个不为null的,然后返回

例如
BLPOP list1 list2 list3 0 假设 list1 为 null。 list2、list3 不为 null。则, 返回 list2 中最左端的元素(因为它是从 list1 –> list2 –> list3 这个顺序查起的第一个非空列表)。

阻塞场景

如果所有给定的 key 都不存在或都为空列表,那么 BLPOP 命令将阻塞连接, 直到有另一个客户端给其中的某一个 key 添加了元素为止。

一旦有新的数据出现在其中一个 key 中,那么BLPOP 命令会解除阻塞状态,并且返回该 key 和弹出的元素值。

多客户端被同一个key阻塞后,操作的先后顺序

如果有多个客户端都在执行 BLPOP 命令。如果这些客户端指定的 key 没有重叠的情况,那还好说,相当于单个客户端执行 BLPOP 命令。但如果指定的 key 有重叠的时,操作的先后循序是什么?

情况1

客户端A 、客户端 B 调用的 BLPOP 命令中包含相同的 key,但是该 key 的 元素足够多(>2),此时客户端A 、客户端 B都不会阻塞

情况2

客户端A 、客户端 B 调用的 BLPOP 命令中包含相同的 key,但是该 key 的 元素只要1个,此时先来后到,先执行命令的客户端返回,后执行命令的客户端阻塞

情况3

客户端A 、客户端 B 调用的 BLPOP 命令中包含相同的 key,但是该 key 没有元素,客户端A 、客户端 B 一直阻塞,直到有元素为止。

存在元素后,阻塞时间最长还没有超时的客户端优先执行。

解除阻塞后,如果该客户端又执行了该命令,需要重新排队。

同一个客户端被多key阻塞时的执行情况

上面说的都是多个客户端阻塞同一个key的情况,再看下,同一个客户端阻塞多个key的情况

当一个客户端同时被多个 key 阻塞时,若多个 key 的元素同时可用(可能是因为事务或者某个Lua脚本向多个list添加元素), 那么客户端会解除阻塞,并使用第一个接收到 push 操作的 key(假设它拥有足够的元素为我们的客户端服务,因为有可能存在其他客户端同样是被这个key阻塞着)。

从根本上来说,在执行完每个命令之后,Redis 会把一个所有 key 都获得数据并且至少使一个客户端阻塞了的 list 运行一次。 这个 list 按照新数据的接收时间进行整理,即是从第一个接收数据的 key 到最后一个。在处理每个 key 的时候,只要这个 key 里有元素, Redis就会对所有等待这个key的客户端按照“先进先出”(FIFO)的顺序进行服务。若这个 key 是空的,或者没有客户端在等待这个 key, 那么将会去处理下一个从之前的命令或事务或脚本中获得新数据的 key,如此等等。

阻塞时,key 同时接收到多个元素

BLPOP阻塞时,key 有可能同时接收到多个元素,例如

  • LPUSH mylist a b c
  • 在对同一列表执行多次推送操作的MULTI块的EXEC之后。
  • 使用Redis 2.6或更高版本执行Lua脚本。

当多个元素被推入key中时,BLPOP 在 Redis 2.4和Redis 2.6或更高版本的行为会有所不同。

对于Redis 2.6,阻塞的客户端需要等到其他客户端全部push完之后才开始解除阻塞

Client A:   BLPOP foo 0
Client B:   LPUSH foo a b c
复制代码

如果以上情况是在 Redis 2.6服务器或更高版本的服务器上发生的,则客户端A将返回C,因为在LPUSH命令之后,列表包含c,b,a了该元素,因此从左侧获取元素就意味着要返回c。

相反,Redis 2.4的工作方式不同:在推送操作的上下文中为阻塞客户端提供服务。因此,只要LPUSH foo a b c开始将第一个元素a推送到list中,阻塞客户端就会立即解除阻塞并返回a

在将数据复制或持久存储到AOF文件中时,Redis 2.4的行为会产生很多问题,因此Redis 2.6中引入了更为通用和语义上更简单的行为来防止出现问题。

请注意,出于相同的原因,Lua脚本或MULTI/EXEC块可能会将元素推入列表,然后再删除列表。在这种情况下,只要在执行单个命令,事务或脚本之后list中没有数据,就完全不会为被阻止的客户端提供服务,并且将继续被阻止。

实际应用

可以利于 BLPOP 的特性,用 Redis 的 list 实现消息队列。

BLPOP 就相当于一个***,监听 list 中的消息,有数据就返回,没有就一直监听

BRPOP : 右端弹出(阻塞式)

起始版本 : 2.0.0
时间复杂度 : O(1)

(阻塞式)删除(弹出)最右端的元素

BRPOPBLPOP 语法、返回值、实现细节都相同,唯一的区别就是一个是右端弹出一个是左端弹出

相关的细节参考 BLPOP 命令

语法

BRPOP key1 [key2] timeout

timeout 是发生阻塞时的超时时间,单位秒。如果想一种阻塞下去,需要设置为 0。

返回值

  • nil : 直到超时也没有弹出元素
  • 弹出元素的key : 弹出元素的值

 

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务