10.list列表

  • Redis list(列表)是简单的字符串列表,相当于 Java 语言中的 LinkedList 结构,是一个链表而非数组,其插入、删除元素的时间复杂度为 O(1),但是查询速度差,时间复杂度为 O(n)。
  • 当向列表中添加元素值时,首先需要给这个列表指定一个 key 键,若是键不存在,建立新的链表,然后使用相应的命令,从列表的左侧(头部)或者右侧(尾部)来添加元素,这些元素会以添加时的顺序排列。一个列表最多可以包含 2^32 - 1 个元素(约 40 亿个元素),当列表弹出最后一个元素时,该结构会被自动删除。

链表的操做不管是头和尾效率都极高,但假如是对中间元素进行操做,效率就很差了

  • Redis 列表的底层存储结构,其实是一个被称为快速链表(quicklist)的结构。当列表中存储的元素较少时,Redis 会使用一块连续的内存来存储这些元素,这个连续的结构被称为 ziplist(压缩列表),它将所有的元素紧挨着一起存储。

压缩列表是 Redis 为节省内存而开发的,它是由一系列特殊编码的连续内存块组成的顺序型数据结构,一个压缩列表了可以包含任意多个节点,每个节点都可以保存一个字符数组或者整数值。

  • 而当数据量较大时,Redis 列表就会是用普通链表存储元素。Redis 之所以采用两种方法相结合的方式来存储元素。这是因为单独使用普通链表存储元素时,所需的空间较大,会造成存储空间的浪费。因此采用了链表和压缩列表相结合的方式,也就是 quicklist + ziplist,结构如下图:

在这里插入图片描述

  • 上图所示,将多个 ziplist 使用双向指针串联起来,这样既能满足快速插入、删除的特性,又节省了一部分存储空间。

  • 使用命令操作 Redis 列表。示例:如何从列表的左侧、右侧添加和弹出元素。

#从左侧头部插入元素
remote:0>lpush listcontext php java C++
"3"
remote:0>lpush listcontext php java C++
"6"
#查看插入的元素
remote:0>lrange listcontext 0 5
 1)  "C++"
 2)  "java"
 3)  "php"
 4)  "C++"
 5)  "java"
 6)  "php"
 #从右侧尾部插入元素
 remote:0>rpush listcontext dubbo c# lua
"9"
remote:0>rpush listcontext dubbo c# lua
"12"
#查看元素
remote:0>lrange listcontext 0 14
 1)  "C++"
 2)  "java"
 3)  "php"
 4)  "C++"
 5)  "java"
 6)  "php"
 7)  "C++"
 8)  "java"
 9)  "php"
 10)  "dubbo"
 11)  "c#"
 12)  "lua"
 13)  "dubbo"
 14)  "c#"
 15)  "lua"
 #在php前面插入元素
 remote:0>linsert listcontext before php vue
"8"
remote:0>lrange listcontext 0 7
 1)  "C++"
 2)  "java"
 3)  "sql"
 4)  "vue"
 5)  "php"
 6)  "dubbo"
 7)  "c#"
 8)  "lua"
 #从左侧弹出元素
 remote:0>lpop listcontext 
"C++"
 #从右侧弹出元素
 remote:0>rpop listcontext
"dubbo"
10.1 队列和栈实现
  • Redis 列表可以被当做栈、队列、阻塞队列来使用,栈和队列就是操作受限的线性表。如果列表的元素是“左进右出”那就是队列模型(一个一个进出理解);如果元素是“右进右出”那就是栈模型(一个一个进出理解),示例如下:
  • 如果key不存在,创建新的链表。
  • 如果key存在,新增内容。
  • 如果移除了所有值,空链表代表不存在!
  • 在两边插入或者改动值,效率最高!操作中间元素,相对来说效率会低一点。
  • 左进右出,LPUSH 命令将一个或多个值插入到列表头部从左侧开始操作),如果有多个 value 值,那么各个 value 值从左到右的顺序依次插入。
remote:0>lpush course c java ai
"3"

remote:0>rpop course
"c"

remote:0>rpop course
"java"

remote:0>rpop course
"ai"
  • 右进左出
remote:0>rpush course c java ai
"3"
remote:0>lpop course
"c"
remote:0>lpop course
"java"
remote:0>lpop course
"ai"
remote:0>lpop course
null
remote:0>lrange course 0 2

  • 右进右出
remote:0>rpush course c java ai
"3"
remote:0>rremote:0>pop course
"ai"
remote:0>rpop course
"java"
remote:0>rpop course
"c"
remote:0>rpop course
null
  • 除上述模型外,Redis 的列表也常被用作异步队列。使用流程大致如下:一个线程将需要延时处理的任务序列化成字符串,并“塞”进 Redis 列表中,而另外一个线程则以轮询的方式从该列表中读取“任务”。作为消息队列队列、栈的特性可以替代mq进行使用。

list可以记录用户的最近浏览商品记录

10.2 常用命令汇总
  • List 是 Redis 中最常用数据类型之一(单值多value)。Redis 提供了诸多用于操作列表类型的命令,通过这些命令可以实现将一个元素添加到列表的头部,或者尾部等诸多操作。Redis不区分大小命令。
命令说明
LPUSH key value1 [value2]在列表头部插入一个或者多个值。
LRANGE key start stop获取列表指定范围内的元素。
RPUSH key value1 [value2]在列表尾部添加一个或多个值。
LPUSHX key value当储存列表的 key 存在时,用于将值插入到列表头部。
RPUSHX key value当存储列表的 key 存在时,用于将值插入到列表的尾部。
LINDEX key index通过索引获取列表中的元素,都是从零开始。
LINSERT key before|after pivot value指定列表中一个元素在它之前或之后插入另外一个元素。
LREM key count value表示从列表中left往right删除元素与 value 相等的元素。count 表示删除的数量,为 0 表示全部移除,返回的值为实际删除的数量。
LSET key index value表示通过其索引设置列表中元素的值。
LTRIM key start stop保留列表中指定范围内的元素值。
LPOP key从列表的头部弹出元素,默认为第一个元素。
RPOP key从列表的尾部弹出元素,默认为最后一个元素。
LLEN key用于获取列表的长度。
RPOPLPUSH source destination用于删除列表中的最后一个元素,然后将该元素添加到另一个列表的头部,并返回该元素值。
BLPOP key1 [key2 ] timeout用于删除并返回列表中的第一个元素(头部操作),如果列表中没有元素,就会发生阻塞, 直到列表等待超时或发现可弹出元素为止。
BRPOP key1 [key2 ] timeout用于删除并返回列表中的最后一个元素(尾部操作),如果列表中没有元素,就会发生阻塞, 直到列表等待超时或发现可弹出元素为止。
BRPOPLPUSH source destination timeout从列表中取出最后一个元素,并插入到另一个列表的头部。如果列表中没有元素,就会发生 阻塞,直到等待超时或发现可弹出元素时为止。
10.3 BLPOP命令
  • Redis BLPOP 命令是列表弹出元素的阻塞模式,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
  • 当给定多个 key 时,按 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。命令可用版本:>= 2.0.0。 BLPOP 命令的基本语法如下:
BLPOP key [key ...] timeout 
  • BLPOP 命令的返回值:如果列表为空,返回一个 null 。否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key,第二个元素是被弹出元素的值。命令演示:
remote:0>lpush course java c++ c#
"3"
#弹出列表中第一个元素,并返回存储它的key
remote:0>blpop course 5
 1)  "course"
 2)  "c#"
remote:0>blpop course 5
 1)  "course"
 2)  "c++"
remote:0>blpop course 5
 1)  "course"
 2)  "java"
#设置超时时间,否则将一直阻塞
remote:0>blpop course 5

10.4 BRPOP命令
  • BRPOP 命令是 RPOP 的阻塞模式,当给定列表内没有任何元素可供弹出的时候,连接将被 BRPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
  • 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的尾部元素。命令可用版本:>= 2.0.0.BRPOP 命令的基本语法如下:
BRPOP key [key ...] timeout 
  • BRPOP 命令的返回值:假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key,第二个元素是被弹出元素的值。
remote:0>lpush course java c++ c#
"3"
remote:0>brpop course 5
 1)  "course"
 2)  "java"
remote:0>brpop course 5
 1)  "course"
 2)  "c++"
remote:0>brpop course 5
 1)  "course"
 2)  "c#"
remote:0>brpop course 5

10.5 BRPOPLPUSH命令
  • RPOPLPUSH 命令执行以下两步操作:首先将列表(source)中的最后一个元素(尾元素)弹出,并返回给客户端。然后将弹出的元素插入到另外一个指定的列表(destination)中,并作为该列表的的头元素。命令可用版本:>= 1.2.0。BPOPLPUSH 命令的基本语法如下:

非语法糖,语法糖是简写,这个组合命令保证原子性,不算简写

RPOPLPUSH source destination
  • 如果 source 不存在,那么将 返回 null,并且不再执行其他操作。 如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况看做翻转列表操作。

  • BPOPLPUSH 命令的返回值被弹出的元素。

#创建列表并添加元素
remote:0>lpush course java c++ c#
"3"
remote:0>lrange course 0 2
 1)  "c#"
 2)  "c++"
 3)  "java"
#将course的尾部元素弹出,添加到web列表的头部
remote:0>rpoplpush course lesson
"java"
remote:0>rpoplpush course lesson
"c++"
remote:0>rpoplpush course lesson
"c#"
remote:0>rpoplpush course lesson
null
remote:0>lrange lesson 0 2
 1)  "c#"
 2)  "c++"
 3)  "java"
 
#如果 source 和 destination 相同,
remote:0>lpush course java c++ c#
"3"
remote:0>rpoplpush course lesson
"java"
 remote:0>lrange course 0 2
 1)  "c#"
 2)  "c++"
remote:0>lrange lesson 0 4
 1)  "java"
 2)  "c#"
 3)  "c++"
 4)  "java"
10.6 LINDEX命令
  • LINDEX 命令返回列表中,下标为 index 的元素且从上到下。命令可用版本:>= 1.0.0。LINDEX 命令的基本语法如下:
LINDEX key index
  • Redis LINDEX 命令的返回值:列表中下标为 index 的元素。如果 index 参数值超出列表的区间范围(out of range),则返回null。命令演示
remote:0>lrange lesson 0 4
 1)  "java"
 2)  "c#"
 3)  "c++"
 4)  "java"
##下标为0的元素
remote:0>lindex lesson 0
"java"
##超出索引范围返回null
remote:0>lindex lesson 4
null
remote:0>lindex lesson 3
"java"
10.7 LINSERT命令
  • Redis LINSERT 命令将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
  • 当 pivot (参照值)不存在于列表 key 时,不执行任何操作。当 key 不存在时, key 被视为空列表,不执行任何操作。如果 key 不是列表类型,返回一个错误。命令可用版本:>= 2.2.0。LINSERT 命令的基本语法如下:
 LINSERT key BEFORE|AFTER pivot value
  • LINSERT 命令的返回值:如果命令执行成功,返回插入操作完成之后,列表的长度;如果没有找到 pivot ,返回 -1 。如果 key 不存在或为空列表,返回 0 。命令演示
#同时添加多个value
remote:0>lpush lesson java c# php
"3"
 #在c#之前添加提个值
remote:0>linsert lesson before c# php
"4"
 #在c#之后添加一个值
remote:0>linsert lesson after c# php
"5"
 #在redis之后添加一个值
remote:0>linsert lesson after c## php
"-1"
#浏览列表中所有元素
remote:0>lrange lesson 0 8
 1)  "php"
 2)  "php"
 3)  "c#"
 4)  "php"
 5)  "java"
10.8 LLEN命令
  • LLEN命令返回列表 key 的长度。如果 key 不是列表类型,返回一个错误。命令可用版本:>= 1.0.0。LLEN 命令的基本语法如下:
LLEN key   
  • LLEN 命令的返回值列表 key 的长度。命令演示
remote:0>lrange lesson 0 8
 1)  "php"
 2)  "php"
 3)  "c#"
 4)  "php"
 5)  "java"
#查看长度
remote:0>llen lesson
"5"
10.9 LPOP命令
  • LPOP 命令移除并返回列表 key 的头元素。命令可用版本:>= 1.0.0。LPOP 命令的基本语法如下:
LPOP key 
  • LPOP 命令的返回值是列表的头部的第一个元素。当 key 不存在时,则返回 null 。命令演示:
#同时添加多个value
remote:0>lpush lesson java c++ php
"3"
#添加重复的值
remote:0>lpush lesson java c++ php
"6"
#只添加一个值
remote:0>lpush lesson sql
"7"
#从左侧头部弹出第一个元素
remote:0>lpop lesson
"sql"
10.10 LPUSH、LPUSHX命令
  • LPUSH 命令将一个或多个值插入到列表头部从左侧开始操作),如果有多个 value 值,那么各个 value 值从左到右的顺序依次插入。如果 key 不存在,那么一个空列表会被自动创建并执行 LPUSH 操作;当 key 存在但不是列表类型时,则返回一个错误。 命令可用版本:>= 1.0.0
注意:在 Redis 2.4 版本以前的 LPUSH 命令,都只接受单个 value 值。
左进右为顶;右进右为底
  • LPUSHX 命令,当且仅当 key 存在,并且类型为列表时,将值 value 插入到列表的头部。和 LPUSH 命令相反,当 key 不存在时, LPUSHX 命令什么也不执行。命令可用版本:>= 2.2.0

  • 命令的基本语法如下:

#LPUSH 命令的基本语法如下:
LPUSH key value [value ...]  
#LPUSHX 命令的基本语法如下:
LPUSHX key value 
  • LPUSH 命令的返回值:执行 LPUSH 命令后,返回列表中元数的的个数。即列表的长度。
  • LPUSHX 命令的返回值:表的长度。命令演示:
#同时添加多个value,左进右为顶;右进右为底
remote:0>lpush lesson java c++ php
"3"
#添加重复的值
remote:0>lpush lesson java c++ php
"6"
#只添加一个值
remote:0>lpush lesson sql
"7"
remote:0>set name zs
"OK"
#类型不符,name是字符串类型的key
remote:0>lpush name ls
"WRONGTYPE Operation against a key holding the wrong kind of value"

#执行lpushx命令,添加成功并返回元素的个数
remote:0>lpushx lesson c#
"7"
#添加不存在的key,则失败
remote:0>lpushx lessons c#
"0"
10.11 LRANGE命令
  • Redis LRANGE 命令返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
  • 下标(index)参数 start 和 stop 都是以 0 开始,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素。命令可用版本:>= 1.0.0

注意:LRANGE 命令是一个闭区间操作,取值范围包括 stop 值。它不同于 Python 的 range()函数。

  • Redis LRANGE 命令的基本语法如下:
LRANGE key start stop 
  • LRANGE 命令的返回值:一个列表,包含指定区间内的元素。
#同时添加多个value
remote:0>lpush lesson java c++ php
"3"
#查看元素
remote:0>lrange lesson 0 8
 1)  "php"
 2)  "c++"
 3)  "java"
10.12 LREM命令
  • LREM 命令根据 count 的值,移除列表中与参数 value 相等的元素。命令可用版本:>= 1.0.0。场景:取关特定的值。

  • count 取值有以下几种情况:

    • count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
    • count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
    • count = 0 : 移除表中所有与 value 相等的值。
  • LREM 命令的基本语法如下:

LREM key count value 
  • LREM 命令的返回值被移除元素的数量。若 key 不存在时, 则 LREM 命令总是返回 0 。
remote:0>lpush lesson java c++ php
"3"
remote:0>lpush lesson java c++ php
"6"
remote:0>lpush lesson java c++ php
"9"
#count决定删除数量,这里取其绝对值
remote:0>lrem lesson 2 php
"2"
remote:0>lrange lesson 0 20
 1)  "c++"
 2)  "java"
 3)  "c++"
 4)  "java"
 5)  "php"
 6)  "c++"
 7)  "java"
remote:0>lrem lesson -2 java
"2"
remote:0>lrange lesson 0 20
 1)  "c++"
 2)  "java"
 3)  "c++"
 4)  "php"
 5)  "c++"
10.13 LSET 命令
  • LSET 命令能够将列表中下标为 index 的元素的值设置为 value。当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,将会返回一个错误。命令可用版本:>= 1.0.0。LSET 命令的基本语法如下:
LSET key index value  
  • LSET 命令的返回值:操作成功返回 ok ,否则返回错误信息。命令演示
remote:0>lrange lesson 0 20
 1)  "c++"
 2)  "java"
 3)  "c++"
 4)  "php"
 5)  "c++"
#更改值
remote:0>lset lesson 0 C#
"OK"
remote:0>lrange lesson 0 10
 1)  "C#"
 2)  "java"
 3)  "c++"
 4)  "php"
 5)  "c++"
#index 参数超出范围
remote:0>lset lesson 8 C#
"ERR index out of range"

10.14 LTRIM命令
  • LTRIM 命令对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除,然后再赋值给key。命令可用版本:>= 1.0.0。LTRIM 命令的基本语法如下:
 LTRIM key start stop 

注意:如果 start 的值大于列表的最大长度,或者 start > stop,那么 LTRIM 命令会将整个列表清空,并返回一个空列表。

  • LTRIM 命令的返回值操作成功返回 ok ,否则返回错误信息。命令演示
remote:0>lrange lesson 0 10
 1)  "C#"
 2)  "java"
 3)  "c++"
 4)  "php"
 5)  "c++"
 #裁剪元素只保留三个元素
remote:0>ltrim lesson 1 3
"OK"
#查看结果
remote:0>lrange lesson 0 10
 1)  "java"
 2)  "c++"
 3)  "php"
下一篇:redis学习-15- Redis hash哈希散列
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐