介绍
列表类型可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。列表类型内部是使用双向链表实现的,所以向列表两端添加元素的时间复杂度为0(1),获取越接近两端的元素速度就越快。不过通过索引访问元素就比较慢了。
列表类型能非常快速地完成关系数据库难以应付的场景:如社交网站的新鲜事,我们关心的只是最新的内容,使用列表类型存储,即使新鲜事的总数达到几千万个,获取其中最新的100条数据也是极快的。同样因为在两端插入记录的时间复杂度是0(1),列表类型也适合用来记录日志,可以保证加入新日志的速度不会受到已有日志数量的影响。一个列表类型键最多能容纳2^32-1个元素。
一、列表类型特点
特点:
- 有序的(插入顺序)
- 可以重复的
- 左右两边插入弹出
二、应用场景
场景一:微博的时间轴功能TimeLine,取数据做分页
- 微博按照发表时间倒序排列
- 按照一定范围(每10条数据)做分页
场景二:抢红包
127.0.0.1:6379> FLUSHALLOK127.0.0.1:6379> LPUSH k1 2 4 1 3(integer) 4127.0.0.1:6379> RPOP k1"2"127.0.0.1:6379> RPOP k1"4"127.0.0.1:6379> RPOP k1"1"127.0.0.1:6379> RPOP k1"3"
三、命令拾遗
127.0.0.1:6379> help @list BLPOP key [key ...] timeout summary: Remove and get the first element in a list, or block until one is available since: 2.0.0 BRPOP key [key ...] timeout summary: Remove and get the last element in a list, or block until one is available since: 2.0.0 BRPOPLPUSH source destination timeout summary: Pop a value from a list, push it to another list and return it; or block until one is available since: 2.2.0 LINDEX key index summary: Get an element from a list by its index since: 1.0.0 LINSERT key BEFORE|AFTER pivot value summary: Insert an element before or after another element in a list since: 2.2.0 LLEN key summary: Get the length of a list since: 1.0.0 LPOP key summary: Remove and get the first element in a list since: 1.0.0 LPUSH key value [value ...] summary: Prepend one or multiple values to a list since: 1.0.0 LPUSHX key value summary: Prepend a value to a list, only if the list exists since: 2.2.0 LRANGE key start stop summary: Get a range of elements from a list since: 1.0.0 LREM key count value summary: Remove elements from a list since: 1.0.0 LSET key index value summary: Set the value of an element in a list by its index since: 1.0.0 LTRIM key start stop summary: Trim a list to the specified range since: 1.0.0 RPOP key summary: Remove and get the last element in a list since: 1.0.0 RPOPLPUSH source destination summary: Remove the last element in a list, prepend it to another list and return it since: 1.2.0 RPUSH key value [value ...] summary: Append one or multiple values to a list since: 1.0.0 RPUSHX key value summary: Append a value to a list, only if the list exists since: 2.2.0127.0.0.1:6379>
命令演示
1. LPUSH(左边添加)和RPUSH(右边添加)
list是有序的,数据的放入顺序,返回值表示增加元素后列表的长度:
127.0.0.1:6379> lpush k1 a b c d e(integer) 5127.0.0.1:6379> LRANGE k1 0 -11) "e"2) "d"3) "c"4) "b"5) "a"127.0.0.1:6379> rpush k1 x y z(integer) 8127.0.0.1:6379> LRANGE k1 0 -11) "e"2) "d"3) "c"4) "b"5) "a"6) "x"7) "y"8) "z"127.0.0.1:6379>
2. LPOP(左边弹出)和RPOP(右边弹出)
LPOP命令执行两步操作:第一步是 将列表左边的元素从列表中移除,第二步是返回被移除的元素值。例如:
127.0.0.1:6379> LPOP k1"e"127.0.0.1:6379> RPOP k1"z"127.0.0.1:6379>
可以使用列表模拟栈和队列操作:
- 同向(左压左出或右压右出):栈
- 异向(左压右出或右压左出):队列
3. LINDEX(根据下标获取元素值)和LSET(通过索引赋值)
127.0.0.1:6379> LINDEX k1 3"a"127.0.0.1:6379> LINDEX k1 5"y"127.0.0.1:6379>lset k1 5 "yy"OK127.0.0.1:6379> LINDEX k1 5"yy"
- 可以用来模拟数组
- 如果index是负数则表示从右边开始计算的索引,最右边元素的索引是-1
4. LLEN(获取列表中元素个数)
当键不存在时返回0:
127.0.0.1:6379> llen num(integer) 0127.0.0.1:6379> llen k1(integer) 6
LLEN命令的功能类似SQL语句SELECT COUNT(*) FROM TABLE_NAME,但是LLEN的时间复杂度是O(1),使用时Redis会直接读取现成的值,而不需要像InnoDB那样需要遍历一遍数据表来统计数量。
5. LRANGE(获取列表片段)
Redis的列表起始索引是0:
127.0.0.1:6379> LRANGE k1 0 -11) "e"2) "d"3) "c"4) "b"5) "a"6) "x"7) "y"8) "z"
LRANGE命令也支持负索引,表示从右边开始计算序数,如"-1"表示最右边第一个元 素,"-2"表示最右边第二个元素,依次类推。特殊情况:
- 如果start的索引位置比stop的索引位置靠后,则会返回空列表
- 如果stop大于实际的索引范围,则会返回到列表最右边的元素
6. LREM(删除列表中指定的值)
LREM命令会删除列表中前count个值为value的元素,返回值是实际删除的元素个数。根据count值的不同,LREM命令的执行方式会略有差异:
- 当count>0时LREM命令会从列表左边开始删除前count个值为value的元素
- 当count<0时LREM 命令会从列表右边开始删除前|count|个值为value的元素
- 当count=0时LREM命令会删除所有值为value的元素
// 从右边开始删除第一个值为"y"的元素127.0.0.1:6379> lrem k1 -1 "y"(integer) 1127.0.0.1:6379> LRANGE k1 0 -11) "e"2) "d"3) "c"4) "b"5) "a"6) "x"7) "z"
7. LTRIM(删除区间之外的数据)
127.0.0.1:6379> LRANGE k1 0 -11) "d"2) "c"3) "b"4) "a"5) "x"6) "y"127.0.0.1:6379> LTRIM k1 0 -1OK127.0.0.1:6379> LRANGE k1 0 -11) "d"2) "c"3) "b"4) "a"5) "x"6) "y"127.0.0.1:6379> LTRIM k1 0 4OK127.0.0.1:6379> LRANGE k1 0 -11) "d"2) "c"3) "b"4) "a"5) "x"127.0.0.1:6379>
- 可以用来保留热数据
- 删除中间的没有办法(可以分多次删两边的)
8. LINSERT(向列表中插入元素)
LINSERT key BEFORE|AFTER pivot value。LINSERT命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是 BEFORE还是AFTER来决定将value插入到该元素的前面还是后面:
127.0.0.1:6379> LRANGE k1 0 -11) "d"2) "c"3) "b"4) "a"5) "x"127.0.0.1:6379> linsert k1 after "a" "w"(integer) 6127.0.0.1:6379> LRANGE k1 0 -11) "d"2) "c"3) "b"4) "a"5) "w"6) "x"
9. POPLPUSH(将元素从一个列表转到另一个列表)
先执行RPOP命令再执行 LPUSH 命令。RPOPLPUSH命令会先从source列表类型键的右边弹出一个元素,然后将其加入到destination列表类型键的左边,并返回这个元素的值,整个过程是原子的。
当把列表类型作为队列使用时,RPOPLPUSH命令可以很直观地在多个队列中传递数据。当source和destination相同时,RPOPLPUSH命令会不断地将队尾的元素移到队首,借助这个特性我们可以实现一个网站监控系统:使用一个队列存储需要监控的网址,然后监控程序不断地使用RPOPLPUSH命令循环取出一个网址来测试可用性。这里使用RPOPLPUSH命令的好处在于在程序执行过程中仍然可以不断地向网址列表中加入新网址,而且整个系统容易扩展,允 许多个客户端同时处理队列。
四、列表总结
- LRUSH + LPOP = Stack
- LPUSH + RPOP = Queue
- LPUSH + LTRIM = Capped Collection
- LPUSH + BRPOP = Message Queue