Redis中还有一个常用的类型——Lists。如果你接触过Python语言,那么你应该知道Python中也有List类型,不同的是:Python中的List类型其实就是一个数组,而Redis中的List类型底层则是用链表(Linked Lists)实现的。
众所周知的,数组和链表由于底层实现机制不同,各自的特性也因此不同。由于Redis的List类型是通过链表实现的,这意味着不管Lists中有多少元素,我们都可以实现在Lists头或尾以常数时间完成新元素的添加操作。但是,带来的缺点是,它不能像数组那样通过索引进行元素的快速访问。
1.LPUSH/RPUSH/LRANGE
(1)LPUSH/RPUSH
LPUSH命令用来向list头部(即左边)添加一个新的元素;类似的,RPUSH命令用来向list尾部(右边)添加一个新的元素。
命令格式:
1 2 |
LPUSH key value [value …] RPUSH key value [value …] |
类似的,还有LPUSHX/RPUSHX命令,不同的是这两个命令只有当指定的list存在时才会操作。
(2)LRANGE
LRANGE命令用来从list指定范围中提取元素。
命令格式:
1 |
LRANGE key start stop |
start, stop分别表示范围的开始和结束,-1表示最后一个元素。
(3)示例
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> RPUSH mylist A (integer) 1 127.0.0.1:6379> RPUSH mylist B (integer) 2 127.0.0.1:6379> LPUSH mylist first (integer) 3 127.0.0.1:6379> LRANGE mylist 0 -1 1) "first" 2) "A" 3) "B" |
2.RPOP/LPOP
RPOP和LPOP命令,分别用来从list的尾部或头部弹出一个元素。
(1)命令格式
1 2 |
RPOP key LPOP key |
(2)示例
1 2 3 4 5 6 |
127.0.0.1:6379> RPUSH mylist a b c (integer) 3 127.0.0.1:6379> rpop mylist "c" 127.0.0.1:6379> lpop mylist "a" |
3.LTRIM
LTRIM命令跟LRANGE命令最大的不同点在于LTRIM命令会改变原有的list,而LRANGE却不会。
(1)命令格式
1 |
LTRIM key start stop |
(2)示例
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> del mylist (integer) 1 127.0.0.1:6379> RPUSH mylist 1 2 3 4 5 (integer) 5 127.0.0.1:6379> LTRIM mylist 0 2 OK 127.0.0.1:6379> LRANGE mylist 0 -1 1) "1" 2) "2" 3) "3" |
4.BRPOP/BLPOP
List还有一个特性,可以用于实现一个队列,通常可以作为进程间通信系统中的阻塞操作。假设我们有两个进程,其中一个进程需要将某些对象放入list中;另一个进程需要从list中消费这些对象。那么我们可以这样做:首先,使用LPUSH命令将对象添加到list的头部;然后,使用RPOP命令从list的尾部消费这些对象。
然而,当list为空时,RPOP将无对象可供消费,自然会返回NULL。该怎么办呢?难道我们要不停的调用RPOP命令来不断尝试消费吗?对此,Redis提供了BRPOP, BLPOP命令可以用来进行阻塞调用:即一次调用,直到list有数据时才会返回(在没超时的情况下)。
简言之,BRPOP是阻塞版的RPOP。
(1)命令格式
1 2 |
BRPOP key [key ...] timeout BLPOP key [key ...] timeout |
其中,需要注意的几点是:
1)多个客户端同时阻塞在一个list对象上时,服务端将根据客户端阻塞的先后顺序进行元素的投递;
2)与RPOP或LPOP的返回值不同点在于:阻塞版的POP操作不仅返回被弹出的元素,还会返回相应的key。这是因为阻塞版的POP操作可以同时作用在多个list对象上;
3)参数timeout指定的时间超时之后,返回NULL。
(2)示例
1 2 3 4 5 6 7 |
127.0.0.1:6379> DEL list1 list2 (integer) 0 127.0.0.1:6379> RPUSH list1 a b c (integer) 3 127.0.0.1:6379> BRPOP list1 list2 0 1) "list1" 2) "c" |
5.RPOPLPUSH/BRPOPLPUSH
(1)RPOPLPUSH
1 |
RPOPLPUSH source destination |
该命令是个原子操作:返回并移除source中存储的最后一个元素,并将该元素添加到destination的头部。
有如下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
127.0.0.1:6379> RPUSH source a b c (integer) 3 127.0.0.1:6379> RPUSH destination x y z (integer) 3 127.0.0.1:6379> RPOPLPUSH source destination "c" 127.0.0.1:6379> LRANGE source 0 -1 1) "a" 2) "b" 127.0.0.1:6379> LRANGE destination 0 -1 1) "c" 2) "x" 3) "y" 4) "z" |
(2)BRPOPLPUSH
该命令则是RPOPLPUSH的阻塞版本。当source为空时,操作将会阻塞。
6.LINDEX/LLEN/LSET
(1)LINDEX
该命令返回list元素index对应的值,命令格式:
1 |
LINDEX key index |
示例:
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> LPUSH list "world" (integer) 1 127.0.0.1:6379> LPUSH list "hello" (integer) 2 127.0.0.1:6379> LINDEX list 0 "hello" 127.0.0.1:6379> LINDEX list -1 "world" 127.0.0.1:6379> LINDEX list 3 (nil) |
(2)LLEN
该命令返回list的长度,命令格式:
1 |
LLEN key |
示例:
1 2 3 4 5 6 |
127.0.0.1:6379> LPUSH mylist world (integer) 1 127.0.0.1:6379> LPUSH mylist hello (integer) 2 127.0.0.1:6379> LLEN mylist (integer) 2 |
(3)LSET
该命令可以设置指定索引对应的值,命令格式:
1 |
LSET key index value |
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
127.0.0.1:6379> DEL mylist (integer) 1 127.0.0.1:6379> RPUSH mylist one (integer) 1 127.0.0.1:6379> RPUSH mylist two (integer) 2 127.0.0.1:6379> RPUSH mylist three (integer) 3 127.0.0.1:6379> LSET mylist 0 four OK 127.0.0.1:6379> LSET mylist -2 five OK 127.0.0.1:6379> LRANGE mylist 0 -1 1) "four" 2) "five" 3) "three" |
7.LINSERT
1 |
LINSERT key BEFORE|AFTER pivot value |
该命令可以在pivot前或后插入value,比如:
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> RPUSH mylist "Hello" (integer) 1 127.0.0.1:6379> RPUSH mylist "World" (integer) 2 127.0.0.1:6379> LINSERT mylist BEFORE "World" "There" (integer) 3 127.0.0.1:6379> LRANGE mylist 0 -1 1) "Hello" 2) "There" 3) "World" |
8.其他
这里还是要说明一下list类型的一些特性(也适用于其他Redis类型):
(1)当向list类型添加元素时,如果目标key不存在,那么在添加元素之前,Redis会自动创建一个空的list对象:
1 2 3 4 |
127.0.0.1:6379> DEL mylist (integer) 1 127.0.0.1:6379> LPUSH mylist 1 2 3 (integer) 3 |
(2)当从list对象中删除元素后,如果value为空,那么Redis会自动销毁相应的key:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
127.0.0.1:6379> LPUSH mylist 1 2 3 (integer) 3 127.0.0.1:6379> del mylist (integer) 1 127.0.0.1:6379> LPUSH mylist 1 2 3 (integer) 3 127.0.0.1:6379> EXISTS mylist (integer) 1 127.0.0.1:6379> LPOP mylist "3" 127.0.0.1:6379> LPOP mylist "2" 127.0.0.1:6379> LPOP mylist "1" 127.0.0.1:6379> EXISTS mylist (integer) 0 |
参考:
https://redis.io/topics/data-types-intro
https://redis.io/commands#list