简介
List类型是一个链表结构的集合,其主要功能有push,pop,获取元素等,更详细的说,List类型是一个双端链表的结构,我们可以通过相关的操作进行集合的头部或者尾部添加或删除元素,List的设计非常灵巧,既可以作为栈,也可以作为队列,满足大多数要求。
按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含2的32次方-1(每个列表超过40亿个元素),类似于JAVA的LinkedList
其中list、set、hash、zset这四种数据结构是容器型数据结构,它们共享下面两条通用规则:
- create if not exists:容器不存在则创建
- drop if no elements:如果容器中没有元素,则立即删除容器,释放内存
list(列表)的内部结构
Redis的列表相当于Java语言中的LinkedList,它是一个双向链表数据结构(但是这个结构设计比较巧妙,后面会介绍),支持前后顺序遍历。链表结构插入和删除操作快,时间复杂度O(1),查询慢,时间复杂度O(n)。
list(列表)的使用场景
根据Redis双向列表的特性,因此其也被用于异步队列的使用。实际开发中将需要延后处理的任务结构体序列化成字符串,放入Redis的队列中,另一个线程从这个列表中获取数据进行后续处理。其流程类似如下的图:
常用命令
赋值语法
LPUSH从左侧添加元素
将一个或多个值插入到列表头部(**从左侧添加**
)
LPUSH KEY value1 [value2]
127.0.0.1:6379> lpush list 0 1 2 3 4 5
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
RPUSH 从右侧添加元素
往列表中添加一个或多个值(从右侧添加
)
RPUSH KEY value [value2]
127.0.0.1:6379> rpush list2 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lrange list2 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
LPUSHX 将一个值插入到已存在列表的头部,如果列表不存在,操作无效
将一个值插入到已存在列表的头部,如果列表不存在,操作无效
LPUSHX KEY value1
127.0.0.1:6379> keys *
1) "list2"
2) "list"
127.0.0.1:6379> LPUSHX s 1
(integer) 0
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
127.0.0.1:6379> lpushx list 6
(integer) 7
127.0.0.1:6379> lrange list 0 -1
1) "6"
2) "5"
3) "4"
4) "3"
5) "2"
6) "1"
7) "0"
RPUSHX 将一个值插入到已存在列表的尾部,如果列表不存在,操作无效
将一个值插入到已存在列表的尾部,如果列表不存在,操作无效
RPUSHX KEY value1
取值语法
LLEN 获取列表长度
获取列表长度
LLEN KEY
127.0.0.1:6379> llen list
(integer) 7
LINDEX 通过索引获取列表中的元素(从上到下)
通过索引获取列表中的元素(从上到下)
LINDEX key index
127.0.0.1:6379> lrange list 0 -1
1) "6"
2) "5"
3) "4"
4) "3"
5) "2"
6) "1"
7) "0"
127.0.0.1:6379> lindex list 0
"6"
LRANGE 获取列表指定范围的元素
获取列表指定范围的元素
LRANGE key start stop
127.0.0.1:6379> lrange list 0 -1
1) "6"
2) "5"
3) "4"
4) "3"
5) "2"
6) "1"
7) "0"
删除语法
LPOP 移出并获取列表的第一个元素(从左侧删除)
移出并获取列表的第一个元素(从左侧删除)
LPOP KEY
127.0.0.1:6379> LRANGE list 0 -1
1) "6"
2) "5"
3) "4"
4) "3"
5) "2"
6) "1"
7) "0"
127.0.0.1:6379> lpop list
"6"
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
RPOP移出列表的最后一个元素,返回值为移除的元素(从右侧删除)
移出列表的最后一个元素,返回值为移除的元素(从右侧删除)
RPOP KEY
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
127.0.0.1:6379> rpop list
"0"
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
BLPOP 移除并获取列表第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
移除并获取列表第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
BLPOP KEY timeout
127.0.0.1:6379> blpop l2 1
(nil)
(1.01s)
在以上实列中,操作被会阻塞,如果直到列表l2中存在数据则会返回第一个元素,否则会等待1秒后返回nil
BRPOP 移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
BRPOP KEY timeout
LTRIM 对一个列表进行修剪,让列表只保留指定区间内的元素,不在指定区间之内的元素都被删除
对一个列表进行修剪,让列表只保留指定区间内的元素,不在指定区间之内的元素都被删除
LTRIM key start stop
127.0.0.1:6379> lrange list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> ltrim list 1 3
OK
127.0.0.1:6379> lrange list 0 -1
1) "4"
2) "3"
3) "2"
LREM删除N个value值
删除N个value值。
LREM KEY
127.0.0.1:6379> rpush list3 1 1 1 2 2 3 3 3 3 4 3
(integer) 11
127.0.0.1:6379> lrange list3 0 -1
1) "1"
2) "1"
3) "1"
4) "2"
5) "2"
6) "3"
7) "3"
8) "3"
9) "3"
10) "4"
11) "3"
127.0.0.1:6379> lrem list3 2 2
(integer) 2
127.0.0.1:6379> lrange list3 0 -1
1) "1"
2) "1"
3) "1"
4) "3"
5) "3"
6) "3"
7) "3"
8) "4"
9) "3"
修改语法
LSET 通过索引设置列表元素的值
通过索引设置列表元素的值
LSET KEY index value
127.0.0.1:6379> lrange list 0 -1
1) "4"
2) "3"
127.0.0.1:6379> lset list 0 0
OK
127.0.0.1:6379> lrange list 0 -1
1) "0"
2) "3"
LINSERT 在列表的元素前或者后插入元素,描述:将值value插入到列表key当中,位于world的之前或者之后
在列表的元素前或者后插入元素,描述:将值value插入到列表key当中,位于world的之前或者之后
LINSERT KEY BEFORE|AFTER world value
127.0.0.1:6379> lrange list 0 -1
1) "0"
2) "3"
127.0.0.1:6379> LINSERT list before 3 2
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "0"
2) "2"
3) "3"
高级命令
RPOPLPUSH 移除列表的最后一个元素,并将该元素添加到另一个列表左侧并返回
RPOPLPUSH source destination
移除列表的最后一个元素,并将该元素添加到另一个列表左侧并返回
127.0.0.1:6379> lrange list1 0 -1
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> lrange list2 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> rpoplpush list1 list2
"1"
127.0.0.1:6379> lrange list2 0 -1
1) "1"
2) "a"
3) "b"
4) "c"
实例描述:
- RPOPLPUSH a1 a2 :集合a1的最后元素移到a2的左侧
- RPOPLPUSH a1 a1 :循环列表,将最后元素移到左侧
127.0.0.1:6379> lrange list1 0 -1
1) "2"
2) "3"
127.0.0.1:6379> rpoplpush list1 list1
"3"
127.0.0.1:6379> lrange list1 0 -1
1) "3"
2) "2"
BRPOPLPUSH source destination timeout
:从列表中弹出一个值,将弹出的元素插入到另一个列表中并返回他,如果列表没有元素会阻塞列表直到等待超时或者发现可弹出元素为止
应用场景
list(列表)深入理解
Redis底层存储list(列表)不是一个简单的LinkedList,而是quicklist ——“快速列表”。关于quicklist是什么,下面会简单介绍,具体源码我也还在学习中,后面大家一起探讨。
quicklist是多个ziplist(压缩列表)组成的双向列表;而这个ziplist(压缩列表)又是什么呢?ziplist指的是一块连续的内存存储空间,Redis底层对于list(列表)的存储,当元素个数少的时候,它会使用一块连续的内存空间来存储,这样可以减少每个元素增加prev和next指针带来的内存消耗,最重要的是可以减少内存碎片化问题。
常见的链表结构示意图
每个node节点元素,都会持有一个prev->执行前一个node节点和next->指向后一个node节点的指针(引用),这种结构虽然支持前后顺序遍历,但是也带来了不小的内存开销,如果node节点仅仅是一个int类型的值,那么可想而知,引用的内存比例将会更大。
ziplist示意图
ziplist是一块连续的内存地址,他们之间无需持有prev和next指针,能通过地址顺序寻址访问。
quicklist示意图
quicklist是由多个ziplist组成的双向链表。