目录
List类型的命令
lpush
lpushx
rpush
lrange
lpop
rpop
lindex
linsert
llen
lrem
ltrim
lset
阻塞命令
阻塞命令的使用场景
1.针对一个非空的列表进行操作
2.针对一个空的列表进行操作
3.针对多个key进行操作.
内部编码
lisi类型的应用场景
存储(班级)信息
消息队列
分频道的消息队列
微博Timeline
列表(List)相当于是数组或者是顺序表.
结构示意图
约定最左侧的元素下标是0,redis的下标支持负数下标.
注意list内部的编码方式并非是一个简单的数组,而是更接近于双端队列.
列表中的元素是有序的,指的并不是其按照元素的数据大小进行排列,而是意味着当你向列表中插入元素时,它们会按照插入的顺序进行排序(比如尾插abc,得到的列表也是abc),并且每个元素都有一个关联的索引值来表示其位置。
列表中的元素是允许重复的.
List类型的命令
lpush
将一个或者多个元素从左侧放入到list中.(头插)
LPUSH key element [element ...]
时间复杂度是O(N),N代表插入元素的个数.
lpushx
当key存在时,将一个或者多个元素从左侧放入到list中,不存在则直接返回.
x->exists.
LPUSHX key element [element ...]
rpush
将一个或者多个元素从右侧放入到list中,尾插.
RPUSH key element [element...........]
时间复杂度是O(N),N代表插入元素的个数.
rpushx,类似与lpushx,尾插,不存在直接返回.
lrange
LRANGE key start stop
对于超出下标的情况,redis会尽可能的获取对应的内容.
lpop
LPOP key
从list左侧取出元素,即头删.
返回的是取出的元素或者nil.
rpop
从list右侧取出元素,尾删.
RPOP key
lindex
LINDEX key index
获取从左数第index位置的元素.
时间复杂度是O(N),N指的是list中元素的个数.
返回的是取出的元素或者是nil.
linsert
LINSERT key <BEFORE | AFTER> pivot element
返回的是插入后list的长度.
时间复杂度是O(N).N代表列表的长度.
如果进行插入的时候,基准值有多个,redis是从左往右找,找到第一个符合基准值的位置.
llen
获取list的长度.
LLEN key
时间复杂度是O(1).
时间复杂度为什么是O(1):这是因为Redis将列表的长度存储在列表对象的内部数据结构中,并且在每次插入或删除元素时都会更新该长度。因此,当执行LLEN命令时,Redis可以直接返回列表的长度,无需遍历整个列表,所以时间复杂度是固定的,与列表的长度无关。
lrem
lrem key count element
count表示要删除的个数,element表示要删除的值.
当count>0时表示从左向右删除元素.
当count<0时表示从右向左删除元素.
当count=0时表示删除全部指定元素.
ltrim
LTRIM key start stop
保留start和stop之间区间内的元素,区间外面的元素就直接被删除了.
lset
LSET key index element
根据下标修改元素.
时间复杂度:O(N).
如果下标越界会直接报错.
阻塞命令
blpop key [key.....] timeout
brpop key [key.....] timeout
blpop和brpop是lpop和rpop的阻塞版本.
相当于我们之前学习的阻塞队列一样.
当队列元素为满的时候,在往里插入元素会阻塞;当队列元素为空的时候,往外取元素也会阻塞.
redis只针对队列为空往外取的时候做了阻塞.因为redis中对于list什么时候为满没有明确的要求.
所以blpop和brpop.
blpop和brpop是lpop和rpop的阻塞版本,和对应的非阻塞版本的作用基本一致,除了:
1.在列表有元素的情况下,阻塞和非阻塞版本表现一致.但是如果列表为空,非阻塞版本会立即执行并返回nil,但阻塞版本会根据timeout阻塞一段时间,期间redis可以执行其他命令,但执行阻塞命令的客户端会表现为阻塞状态.
2.命令中如果设置了多个键,那么会从左向右进行遍历键,一旦有一个键对应的列表可以弹出元素,命令立即返回.
3.如果多个客户端对一个键执行brpop或blpop,最先执行命令的客户端会得到弹出的元素.
阻塞命令的使用场景
1.针对一个非空的列表进行操作
返回的结果是一个二元组,一方面告诉我们当前的数据来自哪个key,一方面告诉我们取到的数据是什么.
2.针对一个空的列表进行操作
返回二元组并且显示阻塞时间.
3.针对多个key进行操作.
内部编码
之前的版本list的内部编码是ziplist(压缩列表)和linkedlist(链表).
和hash类型的类似,当元素个数过多的时候,ziplist会转换为linkedlist;当某个value过长的时候,ziplist也会转换为linkedList.
同样也存在两个配置项:list-max-ziplist-entries和list-max-ziplist-value.
而现在的版本list的内部编码只有一个quicklist.
quicklist相当于是结合了链表和压缩列表.
整体还是一个链表,但是链表的每一个节点是一个压缩列表.
每个压缩列表都不要太大,同时再把多个压缩列表通过链式结构的方式连接起来.
lisi类型的应用场景
存储(班级)信息
用list作为像数组这样的结构,来存储多个元素.
用mysql表示两个表,一个学生表一个班级表.
通过这样的表结构,可以很方便的实现查询指定班级中有哪些同学.
而redis中没有这么强调的查询功能,我们只能设置合适的键值对来实现对应的效果.
学生的个人信息用hash表示,而班级信息我们就可以使用list类型来表示.
通过classStudent:1来获取对应的学生id.
消息队列
redis阻塞消息的队列模型
在当前的场景下,如果列表为空,消费者就会阻塞等待,直到有了数据或者到了timeout时间.
谁先执行brpop命令,谁就可以先拿到新来的数据.
如果消费者不停的brpop,这样的设定就能构成一个轮询的效果.
分频道的消息队列
多个频道的场景非常常见,比如一个短视频,可以有一个频道来传输短视频数据,还可以有一个频道来传输弹幕数据,还可以有一个频道来传输点赞,转发和收藏的数据,可以有一个频道来传输评论数据.
设置成多个频道,就可以在某种数据发生问题的时候,不会对其他数据造成影响.
微博Timeline
1.每篇微博使用hash结构存储.
2.向用户的timeline添加微博.user:<uid>:myblogs作为键.
3.分页获取用户的timeline,例如获取用户1的10篇微博.