redis基本数据类型list

redis实验环境

针对学习redis 我们可以为您提供一套完善的学习环境
点击此处跳转

章节叙述

​ 本章节我们介绍一下List类型,列表(List) 类型是用来存储多个有序的字符串, 如图所示, a、b、 c、 d、 e五个元素从左到右组成了一个有序的列表, 列表中的每个字符串称为元素(element) , 一个列表最多可以存储232-1个元素。 在Redis中, 可以对列表两端插入(push) 和弹出(pop) , 还可以获取指定范围的元素列表、 获取指定索引下标的元素等。 列表是一种比较灵活的数据结构, 它可以充当栈和队列的角色, 在实际开发上有很多应用场景。

列表插入弹出操作

列表类型有两个特点:

  1. 列表中的元素是有序的;
  2. 列表中的元素是可以重复的;
常用命令

我们先按照对 列表的5种操作类型 ,对所有的api进行了一个分类,然后按照分类进行介绍

操作类型操作
增加rpushlpushlinsert
lrange lindex llen
删除lpop rpop lrem ltrim
修改lset
阻塞操作blpop brpop
  1. 1,添加操作

    ​ 首先我们了解到,Redis中的List是一个有序的列表,我们可以在列表的右侧,左侧,或者某个元素的位置上进行插入,相对的Redis给我们提供了以上三个场景的命令,分别是rpushlpushlinsert三个命令,我们依次来演示一下

    • 1,rpush从右侧新增元素(支持单个或者多个),该命令会返回当前所有元素的个数,此时新建的元素在队列的末尾:

      rpush list1 value1 value2 value3
      

      您可以通过lrange list1 0 -1指令来查询列表:

       lrange list1 0 -1
      

      可以看到新插入的数据在列表的末尾。

    • 2,lpush从左侧新增元素(支持单个或者多个),该命令会返回当前所有元素的个数,此时新增的元素在队列的开头位置:

      lpush list1 left1 left2
      

      我们再来查询一下列表:

       lrange list1 0 -1
      

      可以发现新增的元素按照插入时间的倒叙在列表的开头位置。

    • 3,linsert是在指定元素的前或者后插入元素,该命令会返回当前所有元素的个数。首先我们先在上述list1value1前方插入一个元素linsert1

      linsert list1 before value1 linsert1
      

      再次查询列表:

       lrange list1 0 -1
      

      可以看到 linsert1确实位于位于value1的上方

      我们再向上述list1value1后方插入一个元素linsert1

      linsert list1 after value1 linsert1
      

      再查询一下:

       lrange list1 0 -1
      

      如您所见value1的下方也出现了一个linsert1,这也只能的List中的元素是可以重复的

  2. 2,查找

    Redis提供了多种检索List列表的方法,同上述我们使用到的lrange检索指定范围内的元素列表,还提供了获取指定索引元素的方法lindex,以及查询List列表长度的方法llen,下述我们依次介绍一下

    1. 1,lrange获取指定范围内的元素列表

      ​ 这个方法我们在上边已经使用过了,我们来解析一下刚刚使用的命令lrange list1 0 -1其中list1是查询的指定键,后面跟的两个参数分别是开始的索引start,和结束的索引endRedis中的索引下标有两个特:第一, 索引下标从左到右分别是0N-1, 但是从右到左分别是-1-N;第二, lrange中的end选项包含了自身, 这个和很多编程语言不包含end不太相同。 例如想获取列表的第2到第4个元素, 可以执行如下操作:

      lrange list1 1 3
      
    2. lindex可以获取指定索引的元素

      这个方法简单,就不赘述了,我们来一个示例

      lindex list1 1
      
    3. llen这个方法可以获取列表长度

      这个方法同我们前面课程介绍的dbsize一样获取的系统参数,并不是检索的内容,时间复杂度为0(1)

      llen list1
      
  3. 3,删除

    同样的Redis也提供了多重删除List中元素的方法分别是:lpop从左侧弹出,rpop从右侧弹出,lrem删除指定元素,ltrim删除指定范围内的元素。老规矩我们还是依次来介绍一下:

    1. 1,lpop从列表的左侧弹出元素,可以指定弹出元素的个数,此结果会返回删除的元素值

      先查询当前的列表

      lrange list1 0 -1
      

      执行指令

      lpop list1 1
      

      再次查询列表:

       lrange list1 0 -1
      
    2. 2,rpop从列表的右侧弹出元素,同样可以指定弹出元素的个数

      rpop list1 1
      

      查询列表:

       lrange list1 0 -1
      

      可以发现在列表的末尾部分,少了一个

    3. lrem删除指定元素

      lrem可以删除指定的元素,它的语法是这样的lrem key count value 这个命令会从列表中找到等于value的元素进行删除, 根据count的不同分为三种情况:

      • count>0, 从左到右, 删除最多count个元素。
      • count<0, 从右到左, 删除最多count绝对值个元素
      • count=0, 删除所有。

      例如:新建一个列表中从左向右插入5个a和两个b。

      lpush list2 a a a a a b b
      

      通过查询可以得知那么当前列表变为“ b b a a a a a”:

      lrange list2 0 -1
      

      下面操作将从列表左边开始删除4个为a的元素:

      lrem list2 4 a
      

      随后我们再次查询列表,看看是否和我们猜想的一样变成了"b b a"

      lrange list2 0 -1
      
    4. 修改操作

      Redis提供了修改指定索引下标元素的方法

      lset list1 0 newval
      
    5. 阻塞操作

      blpop key [key ...] timeout 	
      brpop key [key ...] timeout
      

      ​ 阻塞式弹出有两个命令blpopbrpop这个两个方法是lpoprpop的阻塞版本,它们除了弹出方向不同之后,使用方法基本相同,下面以blpop为例子

      ​ 首先解释一下上述语法:这个方法就是当给定的列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。

      • key [key …] 多个列表的键
      • timeout 阻塞时间(单位秒)

      我们来一个简单的例子实践一下

      首先有两种情况(列表为空和列表不为空的情况)

      我们先创建一个列表

      lpush list3 val3
      

      可以查看一下当前list3中有一个元素val3

       lrange list3 0 -1
      

      我们执行一下BLPOP命令让他阻塞10秒

       blpop list3 10
      

      我们可以发现当列表不为空的时候,它会立即返回结果,并没有进入阻塞等待,返回值为,指定的key以及弹出的值。我现在再来看一下list3的情况

       lrange list3 0 -1
      

      可以发现当前的list3是空的,这时候我们再执行BLPOP命令:

       blpop list3 10
      

      可以看到它在阻塞了10秒之后返回了空,在这期间如果我们插入了元素,那么它会停止阻塞,立即返回,我们来试一下。

      首先我们还是使它处理阻塞等待状态,这次时间稍微长点设置30秒

       blpop list3 30
      

      首先打开新的 terminal窗口点击我打开

      使用指令给list3新建一个元素

      redis-cli lpush list3 new
      

      随后切换为成我们原先的 terminal窗口可以看到,命令并没有阻塞等待30秒自动返回,而是立即返回了我们刚刚新增的new元素

内部编码

接下来我们来了解一下List类型的内部编码。

  • ziplist(压缩列表):当列表的元素个数小于 list-max-ziplist-entries 配置(默认512个),同时列表中每个元素都小于 list-max-ziplist-value 配置时(默认64字节),redis 会选取 ziplist 来作为列表的内部实现来减少内存的使用。

  • linkedlist (链表):当列表类型无法满足 ziplist 的条件是,Redis 会使用 linkedlist 作为列表的内部实现。

    Redis 3.2 版本提供了 quicklist 内部编码,简单地说它是一个 ziplist 为节点的 linkedlist,它结合了 ziplist linkedlist 两者的优势,为列表类型提供了一种更加优秀的内部编码实现,它的设置原理可以参考 Redis 的另一个作者 Matt Stancliff的博客: https://matt.sh/redis-quicklist

使用场景
  1. 消息队列

    Redis lpush + brpop 命令组合即可实现阻塞队列,生产者客户端使用 lrpush 从列表左侧插入元素,多个消费者客户端使用 brpop 命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。

  2. 文章列表

    ​ 对于热点数据的文章列表可以考虑使用 Redis List类型存储,因为列表不但是有序的,同时支持按照索引范围获取元素。可能存在问题如下

    • 如果每次获取的文章个数较多,需要执行多次 hgetall 操作 ,此时可以考虑使用 pipeline (管道)批量获取
    • lrange 命令在列表两端性能较好,但是如果列表较大,获取列表中间范围的元素性能会变差,此时可以考虑将列表作二级拆分,或者使用 Redis3.2quicklist 内部编码实现,它结合 ziplist linkedlist 的特点,获取列表中间范围的元素时也可以高效完成。

实际上列表的使用场景很多,下述是指令组合能达到的 类似数据类型特点

  • lpush + lpop =Stack (栈)

  • lpush + rpop= Queue (队列)

  • lpush + ltrim =Capped Collection (有限集合)

  • lpush + brpop = Message Queue(消息队列)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值