前言
大家好,牧码心今天给大家推荐一篇redis系列—数据结构之列表(list)的文章,在实际工作中有很多应用场景,希望对你有所帮助。内容如下:
- 特点
- 基本命令
- 时间复杂度
- 使用场景
特点
列表(list) 类型是用来存储多个有序的字符串, 如图所示, a、b、 c、 d、 e五个元素从左到右组成了一个有序的列表, 列表中的每个字符串称为元素(element) , 一个列表最多可以存储2的32次方-1个元素。 在Redis中, 可以对列表两端插入(push) 和弹出(pop) , 还可以获取指定范围的元素列表、 获取指定索引下标的元素等 。 列表是一种比较灵活的数据结构, 它可以充当栈和队列的角色, 在实际开发上有很多应用场景。
列表类型有二个显著的特点:
1.列表中的元素是有序的, 这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表;
2.列表中的元素可以是重复的;
基本命令
下面将按照对列表的5种操作类型对命令进行介绍,如图所示:
-
添加
1) 从右边插入元素rpush key value [value ...]
如从右向左插入元素c、b、a
127.0.0. 1:6379> rpush listkey c b a (integer) 3
2) 从左边插入元素,使用方法和rpush相同
lpush key value [value ...]
3) 向某个元素前或者后插入元素
linsert key before|after pivot value
linsert命令会从列表中找到等于pivot的元素, 在其前( before) 或者后( after) 插入一个新的元素value, 例如下面操作会在列表的元素b前插入java
127.0.0.1:6379> linsert listkey before b java (integer) 4
-
查找
1) 获取指定范围内的元素列表lrange key start end
lrange操作会获取列表指定索引范围所有的元素。 索引下标有两个特点:
a.索引下标从左到右分别是0到N-1, 但是从右到左分别是-1到-N
b.lrange中的end选项包含了自身;
例如想获取列表的第2到第4个元素127.0.0.1:6379> lrange listkey 1 3 1) "java" 2) "b" 3) "a"
2) 获取列表指定索引下标的元素
lindex key index
例如当前列表最后一个元素为a:
127.0.0.1:6379> lindex listkey -1 "a
-
删除
1)从列表左侧弹出元素lpop key
2) 从列表右侧弹出
rpop key
3)删除指定元素
lrem key count value
lrem命令会从列表中找到等于value的元素进行删除, 根据count的不同
分为三种情况:
·count>0, 从左到右, 删除最多count个元素。
·count<0, 从右到左, 删除最多count绝对值个元素。
·count=0, 删除所有
例如向列表从左向右插入5个a, 那么当前列表变为“a a a a a java b a”,
下面操作将从列表左边开始删除4个为a的元素:127.0.0.1:6379> lrem listkey 4 a (integer) 4
4)按照索引范围修剪列表
例如, 下面操作会只保留列表listkey第2个到第4个元素:127.0.0.1:6379> ltrim listkey 1 3
-
修改
1)修改指定索引下标的元素:lset key index newValue
下面操作会将列表listkey中的第3个元素设置为python:
127.0.0.1:6379> lset listkey 2 python
-
阻塞
blpop key [key ...] timeout
brpop key [key ...] timeout
blpop和brpop是lpop和rpop的阻塞版本, 它们除了弹出方向不同, 使用方法基本相同, 所以下面以brpop命令进行说明, brpop命令包含两个参数:
·key[key…]: 多个列表的键。
·timeout: 阻塞时间(单位: 秒)。
下面以示例说明:
1) 列表为空: 如果timeout=3, 那么客户端要等到3秒后返回, 如果timeout=0, 那么客户端一直阻塞等下去:
127.0.0.1:6379> brpop list:test 3
(nil)
(3.10s)
127.0.0.1:6379> brpop list:test 0
...阻塞...
如果此期间添加了数据element1, 客户端立即返回:
127.0.0.1:6379> brpop list:test 3
1) "list:test"
2) "element1"
(2.06s)
2) 列表不为空: 客户端会立即返回。
在使用brpop时, 有两点需要注意。
1.如果是多个键, 那么brpop会从左至右遍历键, 一旦有一个键能弹出元素, 客户端立即返回。
127.0.0.1:6379> brpop list:1 list:2 list:3 0
..阻塞..
此时另一个客户端分别向list: 2和list: 3插入元素:
127.0.1.1:6379> lpush list:2 element2
(integer) 1
127.0.1.1:6379> lpush list:3 element3
(integer) 1
客户端会立即返回list: 2中的element2, 因为list: 2最先有可以弹出的
元素:
127.0.0.1:6379> brpop list:1 list:2 list:3 0
1) "list:2"
2) "element2_1"
2.如果多个客户端对同一个键执行brpop, 那么最先执行brpop命令的客户端可以获取到弹出的值。
客户端1:
client-1> brpop list:test 0
...阻塞...
客户端2:
client-2> brpop list:test 0
...阻塞...
客户端3:
client-3> brpop list:test 0
...阻塞...
此时另一个客户端lpush一个元素到list: test列表中:
client-lpush> lpush list:test element
(integer) 1
那么客户端1最会获取到元素, 因为客户端1最先执行brpop, 而客户端2和客户端3继续阻塞:
client> brpop list:test 0
1) "list:test"
2) "element"
时间复杂度
下表列表类型命令的时间复杂度,开发人员可以参考此表选择适合的命令。
使用场景
-
消息队列
Redis的lpush+brpop命令组合即可实现阻塞队列, 生产者客户端使用lrpush从列表左侧插入元素, 多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素, 多个客户端保证了消费的负载均衡和高可用性。如图所示为redis消息队列的模型:
-
实际上列表的使用场景很多, 在选择时可以参考以下口诀:
·lpush+lpop=Stack( 栈)
·lpush+rpop=Queue( 队列)
·lpsh+ltrim=Capped Collection( 有限集合)
·lpush+brpop=Message Queue( 消息队列)
参考
- 《redis开发与运维》