Redis学习手册3—数据结构之列表

列表简介

Redis的列表(list)是一种线性的有序结构(类似于Java中的List集合),可以按照元素的推入列表中的顺序来存储元素,这些元素既可以是文字数据,也可以是二进制数据,并且列表中的元素是可以重复的。

存储结构

Redis的列表键支持左右两端推入(PUSH)或弹出(POP)数据,如下图所示:
在这里插入图片描述

列表支持的功能

Redis为列表提供了丰富的操作命令,通过这些命令,用户可以:

  • 将新元素推入列表的左端或者右端
  • 移除位于列表最左端或者最右端的元素
  • 移除列表最右端的元素,然后把被移除的元素推入另一个列表的左端
  • 获取列表包含的元素数量
  • 获取列表在指定索引上的单个元素,或者获取列表在指定索引范围内的多个元素
  • 为列表的指定索引设置新元素,或者把新元素添加到某个指定元素的前面或后面
  • 对列表进行剪裁,只保留指定索引范围内的元素
  • 从列表中移除指定的元素
  • 执行能够阻塞客户端的推入和移除操作

列表命令速查表

以下表格列举出了Redis针对列表类型键提供的操作命令、用法、参数及其说明:

命令用法及参数说明
LPUSHLPUSH list item [item item ...]将一个或多个元素推入给定列表的左端
RPUSHRPUSH list item [item item ...]将一个或多个元素推入给定列表的右端
LPUSHXLPUSHX list item只在列表存在的情况下将一个元素推入列表左端
RPUSHXRPUSHX list item只在列表存在的情况下将一个元素推入列表右端
LPOPLPOP list从列表最左端弹出一个元素
RPOPRPOP list从列表最右端弹出一个元素
RPOPLPUSHRPOPLPUSH source target从源列表最右端弹出一个元素,然后推入目标列表的最左端
LLENLLEN list获取列表长度,即列表中元素个数
LINDEXLINDEX list index获取指定索引的元素
LRANGELRANGE list start end获取指定索引范围内的元素
LSETLSET list index new_element为指定索引设置新元素
LINSERTLINSERT list BEFORE|AFTER target_element new_element将一个新元素插入到列表某个指定元素的前面或后面
LTRIMLTRIM list start end移除给定索引范围以外的元素,只保留给定范围内的元素
LREMLREM list count element移除列表中的指定的元素,移除规则与 count参数有关,具体参看命令详解
BLPOPBLPOP list [list ...] timeout带阻塞功能的左端弹出操作
BRPOPBRPOP list [list ...] timeout带阻塞功能的右端弹出操作
BRPOPLPUSHBRPOPLPUSH source target timeoutRPOPLPUSH命令的阻塞版本

命令详解

LPUSH命令

用户可以通过LPUSH命令,将一个或多个元素推入指定列表的左端:

LPUSH list item [item item ...]

推入操作执行成功后,LPUSH命令会以当前列表包含的元素数量作为返回值。

127.0.0.1:6379> LPUSH fruits "Apple"
(integer) 1
127.0.0.1:6379> LPUSH fruits "Banana" 
(integer) 2

LPUSH命令执行过程如下图所示:
在这里插入图片描述
如果给定多个元素,那么LPUSH命令将按照顺序依次将元素推入列表左端。

复杂度: O ( N ) O(N) O(N),其中 N N N为被推入列表的元素数量。
版本要求:LPUSH命令从Redis 1.0.0版本开始可用,但是只有Redis 2.4.0或以上版本才支持一次推入多个元素。

RPUSH命令

RPUSH命令和LPUSH命令类似,这两个命令执行的都是元素推入操作,LPUSH命令会将元素推入列表的左端,RPUSH命令会将元素推入列表右端。

RPUSH list item [item item ...]

RPUSH命令执行完毕后,会返回列表当前包含的元素数量作为返回值。

127.0.0.1:6379> RPUSH fruits "Apple"
(integer) 1
127.0.0.1:6379> RPUSH fruits "Banana"
(integer) 2

RPUSH命令执行过程如下图所示:
在这里插入图片描述
如果给定多个元素,那么RPUSH命令将按照顺序依次将元素推入列表右端。

复杂度: O ( 1 ) O(1) O(1),其中 N N N为被推入列表的元素数量。
版本要求:RPUSH命令从Redis 1.0.0版本开始可用,但是只有Redis 2.4.0或以上版本支持一次推入多个元素。

LPUSHX、RPUSHX命令

当用户调用LPUSH命令或RPUSH命令尝试将元素推入列表时,如果给定的列表不存在,那么命令将自动创建一个空列表,并将元素推入列表中,如下所示:

127.0.0.1:6379> LPUSH list1 "item1"
(integer) 1

除了LPUSH命令和RPUSH命令以外,Redis还提供了LPUSHX命令和RPUSHX命令:

LPUSHX list item
RPUSHX list item

这两个命令对待空列表的方式与LPUSHRPUSH命令正好相反:

  • LPUSHX命令只会在列表已经存在的情况下,将元素推入列表左端。
  • RPUSHX命令只会在列表已经存在的情况下,将元素推入列表右端。

如果给定列表并不存在,那么LPUSHX命令和RPUSHX命令将放弃执行推入操作。
如果命令执行成功后,将返回列表当前的长度作为返回值,如果推入操作未能成功执行,那么命令将返回0作为结果。

假设list2列表不存在,执行如下操作:

127.0.0.1:6379> LPUSHX list2 "item-x"
(integer) 0  -- 没有推入任何元素
127.0.0.1:6379> RPUSHX list2 "item-y"
(integer) 0  -- 没有推入任何元素
127.0.0.1:6379> LPUSH list2 "item"
(integer) 1  -- 推入一个元素,使得列表变为非空
127.0.0.1:6379> LPUSHX list2 "item-x"
(integer) 2  -- 执行推入操作之后,列表包含2个元素
127.0.0.1:6379> RPUSHX list2 "item-y"
(integer) 3

注意:与LPUSH命令和RPUSH命令不一样,LPUSHX命令和RPUSHX命令每次只能推入一个元素,尝试推入多个元素将引发错误:

127.0.0.1:6379> LPUSHX list "item1" "item2" "item3"
(error) ERR wrong number of arguments for 'lpushx' command

复杂度: O ( 1 ) O(1) O(1)
版本要求:LPUSHX命令和RPUSHX命令从Redis 2.2.0版本开始可用。

LPOP命令

用户可以通过LPOP命令移除位于列表最左端的元素,并将被移除的元素返回给用户:

LPOP list
127.0.0.1:6379> LPOP fruits
"Apple"
127.0.0.1:6379> LPOP fruits
"Banana"
127.0.0.1:6379> LPOP fruits
(nil)

LPOP命令执行过程如下图所示:
在这里插入图片描述
复杂度: O ( 1 ) O(1) O(1)
版本要求:LPOP命令从Redis 1.0.0版本开始可用。

RPOP命令

LPOP命令类似,RPOP命令可以移除位于列表最右端的元素,并将被移除的元素返回给用户:

RPOP list
127.0.0.1:6379> RPOP fruits
"Banana"
127.0.0.1:6379> RPOP fruits
"Apple"
127.0.0.1:6379> RPOP fruits
(nil)

RPOP命令执行过程如下图所示:
在这里插入图片描述
复杂度: O ( 1 ) O(1) O(1)
版本要求:RPOP命令从Redis 1.0.0版本开始可用。

RPOPLPUSH命令

RPOPLPUSH命令的行为和它的名字一样,首先使用RPOP命令将源列表最右端的元素弹出,然后使用LPUSH命令将被弹出的元素推入目标列表左端,使之称为目标列表的最左端元素:

RPOPLPUSH source target

RPOPLPUSH命令会返回被弹出的元素作为结果。

127.0.0.1:6379> RPUSH list1 "a" "b" "c"
(integer) 3
127.0.0.1:6379> RPUSH list2 "d" "e" "f"
(integer) 3
127.0.0.1:6379> RPOPLPUSH list1 list2
"c"
127.0.0.1:6379> RPOPLPUSH list1 list2
"b"
127.0.0.1:6379> RPOPLPUSH list1 list2
"a"

RPOPLPUSH命令的执行过程如下图所示:
在这里插入图片描述

源列表和目标列表相同

RPOPLPUSH命令允许用户将源里边和目标列表设置为同一个列表,在这种情况下,RPOPLPUSH命令的效果相当于将列表最右端的元素变成列表最左端的元素,如下所示:

127.0.0.1:6379> RPUSH list "a" "b" "c"
(integer) 3
127.0.0.1:6379> RPOPLPUSH list list
"c"
127.0.0.1:6379> RPOPLPUSH list list
"b"
127.0.0.1:6379> RPOPLPUSH list list
"a"

处理空列表

如果传给RPOPLPUSH命令的源列表不存在,那么命令将放弃执行弹出和推入操作,只返回一个空值表示失败:

127.0.0.1:6379> RPOPLPUSH list-x list-y
(nil)

复杂度: O ( 1 ) O(1) O(1)
版本要求:RPOPLPUSH命令从Redis 1.2.0版本开始可用。

LLEN命令

用户可以通过执行LLEN命令来获取列表长度,即列表中包含的元素个数:

LLEN list
127.0.0.1:6379> LLEN fruits
(integer) 2

复杂度: O ( 1 ) O(1) O(1)
版本要求:LLEN命令从Redis 1.0.0版本开始可用。

LINDEX命令

Redis列表包含的每个元素都有与之对应的正是索引和负数索引:

  • 正数索引从列表的最左端计算,依次向右端递增:最左端元素的索引为0,左端第二个索引为 1,以此类推。最大的正数索引为列表长度减1,即 N − 1 N-1 N1
  • 负数索引从列表的最右端开始计算,依次向左递减:最右端元素的索引为 -1,倒数第二个为 -2 以此类推。最大的负数索引为列表长度的负数,即 − N -N N
    在这里插入图片描述
    为了让用户可以方便地取得索引对应的元素,Redis提供了LINDEX命令:
LINDEX list index

LINDEX命令接受一个列表和一个索引作为参数,然后返回列表在给定索引上的元素,其给定的索引即可以是正数,也可以是负数。

127.0.0.1:6379> RPUSH fruits "Apple" "Banana"
(integer) 2
127.0.0.1:6379> LINDEX fruits 0
"Apple"
127.0.0.1:6379> LINDEX fruits 1
"Banana"
127.0.0.1:6379> LINDEX fruits -1
"Banana"
127.0.0.1:6379> LINDEX fruits -2
"Apple"

如果给定的索引超出了索引范围,那么将返回一个空值(nil)。

复杂度: O ( N ) O(N) O(N),其中 N N N为列表长度。
版本要求:LINDEX命令从Redis 1.0.0版本开始可用。

LRANGE命令

除了可以使用LINDEX命令获取给定索引上的单个元素之外,还可以使用LRANGE命令获取给定索引范围上的多个元素:

LRANGE list start end

LRANGE命令接受一个列表、一个开始索引和一个结束索引作为参数,然后依次返回列表从开始索引到结束索引范围内的所有元素,其中开始索引和结束索引对应的元素也包含在命令返回的结果中。

127.0.0.1:6379> LRANGE letters 0 3  -- 获取列表索引0~3上的所有元素
1) "a"
2) "b"
3) "c"
4) "d"

获取列表包含的所有元素

一个快捷地获取列表所有元素的方法,就是使用0作为起始索引、-1作为结束索引去调用LRANGE命令,这种方法非常适合查看长度较短的列表:

127.0.0.1:6379> LRANGE letters 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
7) "g"

处理超出范围的索引

LINDEX一样,LRANGE命令也需要处理超出范围的索引:

  • 如果用户给定的起始索引和结束索引都超出了范围,那么LRANGE命令将返回空列表作为结果。
  • 如果用户给定的其中一个索引超出了范围,那么LRANGE命令将对超出范围的索引进行修正,然后再执行实际的范围获取操作;其中超出范围的起始索引会被修正为0,而超出范围的结束索引则会被修正为-1。
127.0.0.1:6379> LRANGE letters 50 100
(empty list or set)
127.0.0.1:6379> LRANGE letters -100 -50
(empty list or set)
127.0.0.1:6379> LRANGE letters -100 5
1) "a" -- 位于索引0上的元素
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
127.0.0.1:6379> LRANGE letters 5 100
1) "f"  --位于索引5上的元素
2) "g"
3) "h" --位于索引-1上的元素

复杂度: O ( N ) O(N) O(N),其中 N N N为给定列表的长度。
版本要求:LRANGE命令从Redis 1.0.0开始可用。

LSET命令

用户可以同LSET命令,为列表的指定索引设置新元素:

LSET list index new_element

LSET命令在设置成功时返回OK。

127.0.0.1:6379> LRANGE letters 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> LSET letters 1 "d"
OK
127.0.0.1:6379> LRANGE letters 0 -1
1) "a"
2) "d"
3) "c"

处理超出范围的索引

因为LSET命令只能对列表中已存在的索引进行设置,所以如果用户给定的索引超出了列表的有效索引范围,那么LSET命令将返回一个错误:

127.0.0.1:6379> LSET letters 100 "w"
(error) ERR index out of range

复杂度: O ( N ) O(N) O(N),其中 N N N为给定列表的长度
版本要求:LSET命令从Redis 1.0.0开始可用。

LINSERT命令

通过使用LINSERT命令,用户可以将一个新元素插入列表某个指定元素的前面或后面:

LINSERT list BEFORE|AFTER target_element new_element

LINSERT命令第二个参数值可以是BEFORE或者AFTER,分别用于指示命令将新元素插入到目标元素的前面或者后面,插入执行成功后返回当前列表的长度。

127.0.0.1:6379> LRANGE list 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> LINSERT list BEFORE "b" "10086"
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "a"
2) "10086"
3) "b"
4) "c"
127.0.0.1:6379> LINSERT list AFTER "c" "12345"
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "a"
2) "10086"
3) "b"
4) "c"
5) "12345"

处理不存在的元素

LINSERT命令要求用户给定的目标元素必须存在于列表当中。如果给定的目标元素不存在,那么LINSERT命令将返回 -1 表示插入失败:

127.0.0.1:6379> LINSERT list BEFORE "not-exists-element" "new element"
(integer) -1

复杂度: O ( N ) O(N) O(N),其中 N N N为列表的长度。
版本要求:LINSERT命令从Redis 2.2.0版本开始可用。

LTRIM命令

LTRIM命令接受一个列表和一个索引范围作为参数,并移除列表中索引范围以外的元素,只保留给定范围内的元素:

LTRIM list start end

LTRIM命令执行成功后,返回OK。

127.0.0.1:6379> RPUSH letters "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k"
(integer) 11
127.0.0.1:6379> LTRIM letters 0 6
OK
127.0.0.1:6379> LRANGE letters 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
7) "g"
127.0.0.1:6379> LTRIM letters 3 5
OK
127.0.0.1:6379> LRANGE letters 0 -1
1) "d"
2) "e"
3) "f"

LTRIM命令执行过程如下图所示:
在这里插入图片描述

处理负数索引

LRANGE命令一样,LTRIM命令不仅可以处理正数索引,还可以处理负数索引:

127.0.0.1:6379> RPUSH numbers 0 1 2 3 4 5 6 7 8 9
(integer) 10
127.0.0.1:6379> LTRIM numbers -5 -1
OK
127.0.0.1:6379> LRANGE 0 -1
1) "5"
2) "6"
3) "7"
4) "8"
9) "9"

复杂度: O ( N ) O(N) O(N),其中 N N N为列表的长度
版本要求:LTRIM命令从Redis 1.0.0版本开始可用。

LREM命令

用户可以通过LREM命令移除列表中指定的元素:

LREM list count element

count参数的值决定了LREM命令移除元素的方式:

  • 如果count参数的值等于0,那么LREM命令将移除列表中包含的所有指定的元素;
  • 如果count参数的值大于0,那么LREM命令将从列表左端开始向右进行检查,并移除最先发现的count个指定元素;
  • 如果count参数的值小于0,那么LREM命令将从列表的右端开始向左进行检查,并移除最先发现的count个指定元素。

LREM命令执行完成后,返回被移除的元素个数。

127.0.0.1:6379> RPUSH sample1 "a" "b" "b" "a" "c" "c" "a"
(integer) 7
127.0.0.1:6379>RPUSH sample2 "a" "b" "b" "a" "c" "c" "a"
(integer) 7
127.0.0.1:6379> RPUSH sample3 "a" "b" "b" "a" "c" "c" "a"
(integer) 7
127.0.0.1:6379> LREM sample1 0 "a"
(integer) 3 -- 移除了3个"a"元素
127.0.0.1:6379> LRANGE sample1 0 -1
1) "b"
2) "b"
3) "c"
4) "c"
127.0.0.1:6379> LREM sample2 2 "a"
(integer) 2  -- 移除了2个"a"元素
127.0.0.1:6379> LRANGE sample2 0 -1
1) "b"
2) "b"
3) "c"
4) "c"
5) "a"

因为上面的LREM命令只要求移除最先发现的2个"a"元素,所以位于最右端的“a”元素没有被移除,执行过程如下图所示:
在这里插入图片描述
当count<0时,如下所示:

127.0.0.1:6379> LREM sample3 -2 "a"
(integer) 2
127.0.0.1:6379> LRANGE sample3 0 -1
1) "a"
2) "b"
3) "b"
4) "c"
5) "c"

当count<0时,执行过程如下图所示:
在这里插入图片描述
复杂度: O ( N ) O(N) O(N),其中 N N N为列表的长度。
版本要求:LREM命令从Redis 1.0.0版本开始可用。

BLPOP命令

BLPOP命令是带有阻塞功能的左端弹出操作,它接受任意多个列表及一个秒级精度的超时时限作为参数:

BLPOP list [list ...] timeout

BLPOP命令会按照从左到右的顺序依次检查用户给定的列表,并对最先遇到的非空列表执行左端弹出操作。如果BLPOP命令在检查完给定列表后都没有找到可以执行弹出操作的非空列表,那么将阻塞执行该命令的客户端并开始等待,直到某个给定列表变为非空,或者等待时间超出给定的时限为止。

BLPOP命令成功对某个非空列表执行了弹出操作后,将返回一个包含两个元素的数组:数组的第一个元素记录了执行弹出操作的列表,即被弹出元素的来源列表,数组的第二个元素则是被弹出元素本身。

127.0.0.1:6379> BLPOP letters 5  -- 尝试弹出letters列表最左端的元素,最多阻塞5s
1) "letters"
2) "a"

解除阻塞状态

BLPOP命令发现用户给定的所有列表都为空时,就会让执行命令的客户端进入阻塞状态。如果在客户端被阻塞的过程中,有另一个客户端向导致阻塞的列表推入了新的元素,那么该列表就会变为非空,而被阻塞的客户端也会随着BLPOP命令成功弹出列表元素而重新回到非阻塞状态。

下表展示了客户端A从被阻塞到解除阻塞的整个过程:

时间客户端A客户端B
T1执行BLPOP list 10,因为list为空导致客户端被阻塞
T2执行RPUSH list "hello"命令,将"hello"元素推入列表
T3服务器检测到导致客户端阻塞的list列表已经非空,于是从列表弹出"hello"元素并返回给客户端
T4接受到"hello"元素的客户端重新回到非阻塞状态

如果在同一时间有多个客户端因为同一个列表而被阻塞,那么当导致阻塞的列表变为非空时,服务器将按照 “先阻塞先服务” 的规则,依次为被阻塞的客户端弹出列表元素。

处理空列表

如果用户想BLPOP命令传入的所有列表都是空列表,并且这些列表在给定的时限内一直没有变成非空列表,那么BLPOP命令将在给定时限到达之后向客户端返回一个空值,表示没有任何元素被弹出:

127.0.0.1:6379> BLPOP empty-list 5
(nil)
(5.04s)

列表名的作用

BLPOP命令之所以返回被弹出元素的来源列表,是为了在传入多个列表的情况下,让用户知道被弹出元素来自于哪个列表。

阻塞效果的范围

BLPOP命令的阻塞效果只对执行该命令的客户端有效,其他客户端及Redis服务器本身并不会因为这个命令而被阻塞。

复杂度: O ( N ) O(N) O(N),其中 N N N为为用户给定的列表数量。
版本要求:BLPOP命令从Redis 2.0.0版本开始可用。

BRPOP命令

BLPOP命令类似,BRPOP命令是带有阻塞功能的右端弹出操作,除了弹出元素的方向不同,其他与BLPOP命令完全一致。

BRPOP list [list ..] timeout

复杂度: O ( N ) O(N) O(N),其中 N N N为为用户给定的列表数量。
版本要求:BRPOP命令从Redis 2.0.0版本开始可用。

BRPOPLPUSH命令

BRPOPLPUSH命令是RPOPLPUSH命令的阻塞版本,BRPOPLPUSH命令接受一个源列表、一个目标列表以及一个秒级精度的超时实现为参数:

BRPOPLPUSH source target timeout

根据源列表是否为空,BRPOPLPUSH命令会产生以下两种行为:

  • 如果源列表为非空,那么BRPOPLPUSH命令的行为就和RPOPLPUSH命令的行为一样。
  • 如果源列表为空,那么BRPOPLPUSH命令将阻塞执行该命令的客户端,然后在给定时限内等待可弹出的元素出现,或者等待时间超过给定时限为止。

复杂度: O ( 1 ) O(1) O(1)
版本要求:BRPOPLPUSH命令从Redis 2.2.0版本开始可用。

上一篇:Redis学习手册2—数据结构之散列

下一篇:Redis学习手册4—数据结构之集合

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值