Redis数据结构-list
列表
列表的特点
- 列表中的元素是有序的
- 列表中的元素是可重复的
列表从两端插入弹出
命令
添加元素
从左边或右边插入元素
lpush key value [value ...]
rpush key value [value ...]
-------------------------------
> lpush leftkey q w e
3
> lrange leftkey 0 -1
e
w
q
从左查看所有元素
lrange key 0 -1
-------------------------
> lrange leftkey 0 -1
e
w
q
向某个元素前或者后插入元素
linsert key befor|after pivot value
-----------------------------------
> linsert leftkey before e java
5
> lrange leftkey 0 -1
java
e
w
q
r
返回结果是5,表示当前列表长度
查找
查找指定范围元素列表
lrange leftkey start end
-----------------------
> lrange leftkey 0 1
java
e
注意
- 索引下标从左到右是0到N-1,但是从右到左是-1到-N.
- lrange的end包含自身,左闭右闭
查找指定索引下标的元素
lindex key index
---------------------------
> lindex leftkey -1
r
返回列表最后一个元素
获取列表长度
llen key
--------------------
> llen leftkey
5
删除
从列表左侧弹出元素
lpop key
-------------------------
> lrange leftkey 0 -1
e
w
q
r
> lpop leftkey
e
> lrange leftkey 0 -1
w
q
r
相应的,从右侧弹出,rpop key
删除指定元素
lrem key count value
-------------------------------
> lpush testdup a a a b c a
6
> lrem testdup 2 a
2
> lrange testdup 0 -1
c
b
a
a
> lrem testdup 0 a
2
> lrange testdup 0 -1
c
b
lrem命令从列表中找到等于value的元素进行删除,根据count的不同分为三种情况
- count > 0:从左到右,删除等于value的最多count个元素
- count < 0:从右到左,删除等于value的最多count绝对值个元素
- count = 0:删除所有元素
按照索引trim列表
ltrim key start end
-------------------------
> lrange testdup 0 -1
d
c
a
a
a
c
b
> ltrim testdup 1 3
OK
> lrange testdup 0 -1
c
a
a
阻塞操作
blpop key [key ...] timeout
brpop key [key ...] timeout
-----------------------------
空列表
如果对一个空列表执行该命令
> brpop newlist 3
(3s)
null
执行命令,会等待3s,然后返回null,如果timeout=0,客户端会一直等待下去。
直到阻塞期间,向列表中添加元素:
(客户端1)
> brpop testdup 0
(等待...直到客户端插入一个元素)
testdup
a
(客户端2)
> lpush testdup a
1
客户端会立即返回,不再阻塞等待
列表不为空
blpop
立即返回
> lrange testdup 0 -1
b
a
> blpop testdup 3
(立刻返回)
testdup
b
注意:
- 阻塞等待多个key,
brpop
会从左至右遍历键,一旦有一个键能弹出来,客户端立即返回
> blpop key1 key2 key3 0
(等待...直到key1列表添加了元素,返回)
key1
a
- 如果多个客户端对一个key执行
brpop
,那么最先执行brpop
命令的客户端可以获取弹出的值
client1 ->brpop list:test 0
...阻塞...
client2 ->brpop list:test 0
...阻塞...
client3 ->brpop list:test 0
...阻塞...
此时,另一个客户端执行了lpush list:test element
那么客户端1会取到元素,因为它最先执行brpop
,客户端2和3继续阻塞等待。
内部编码
- ziplist
- linkedlist
- quicklist(3.2版本以后默认)
使用场景
- 消息队列
lpush+brpop命令可以实现阻塞队列:lpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式抢列表尾部的元素
- 文章列表
每篇文章可以用哈希结构存储
hmset article:1 title xx timestamp 1276536196 content xxx
文章列表有序,且需要分页展示。可以将文章按顺序缓存到列表里,根据lrange key start end
分页查询文章列表。
返回前10篇文章
lrange user:1:articles 0 9
for article in articles:
hgetall (article)
如果文章数较多,hgetall会多次执行,可以考虑Pipeline批量获取。或者考虑序列化文章变为字符串类型,使用mget批量获取。
另外,如果文章列表较大,lrange在取中间范围的元素的性能会变差。内部编码用quicklist之后,性能会好。(but why?还需要更深入理解内部编码的实现)