本文来说下Redis数据结构之列表

文章目录

  • 概述
  • Redis关于列表的命令
  • 相关命令
    • 添加命令
      • 从右边插入元素
      • 从左边插入元素
      • 向某个元素前或者后插入元素
    • 查询命令
      • 获取指定范围内的元素列表
      • 获取列表指定索引下标的元素
      • 获取列表长度
    • 删除命令
      • 从列表左侧弹出元素
      • 从列表右侧弹出元素
      • 删除指定元素
      • 按照索引范围修剪列表
    • 修改命令
      • 修改指定索引下标的元素
    • 其他操作命令
  • 内部编码
    • ziplist(压缩列表)
    • linkedlist(链表)
  • 应用场景
    • 消息队列
    • 文章列表
    • 其他场景
  • 本文小结

概述

列表(list)类型是用来存储多个 有序 的 字符串。在 Redis 中,可以对列表的 两端 进行 插入(push)和 弹出(pop)操作,还可以获取 指定范围元素列表、获取 指定索引下标 的 元素 等。

列表 是一种比较 灵活 的 数据结构,它可以充当 栈 和 队列 的角色,在实际开发上有很多应用场景

如图所示,a、b、c、d、e 五个元素 从左到右 组成了一个 有序的列表,列表中的每个字符串称为 元素(element),一个列表最多可以存储 2 ^ 32 - 1 个元素。

列表的 插入 和 弹出 操作

列表的 获取、截取 和 删除 操作


Redis关于列表的命令

官网 : https://redis.io/commands#list


相关命令

下面将按照对 列表 的5种 操作类型 对命令进行介绍:


添加命令

从右边插入元素

rpush key value [value …]

下面代码 从右向左 插入元素 c、b、a:

127.0.0.1:6379> rpush mylist c b a
(integer) 3

lrange 0 -1 命令可以 从左到右 获取列表的 所有元素

127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379>

从左边插入元素

lpush key value [value …]

使用方法和 rpush 相同,只不过从 左侧插入,这里不再赘述。


向某个元素前或者后插入元素

linsert key before|after pivot value

linsert 命令会从 列表 中找到 第一个 等于 pivot 的元素,在其 前(before)或者 后(after)插入一个新的元素 value,例如下面操作会在列表的 元素 b 前插入 redis

127.0.0.1:6379> linsert mylist before b redis
(integer) 4

返回结果为 4,代表当前 列表 的 长度,当前列表变为

127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "redis"
3) "b"
4) "a"
127.0.0.1:6379>

查询命令

获取指定范围内的元素列表

lrange key start stop

lrange 操作会获取列表 指定索引 范围所有的元素

索引下标 有两个特点

  • 其一,索引下标 从左到右 分别是 0 到 N-1,但是 从右到左 分别是 -1 到 -N。
  • 其二,lrange 中的 end 选项包含了 自身,这个和很多编程语言不包含 end 不太相同。

从左到右 获取列表的第 2 到第 4 个元素,可以执行如下操作

127.0.0.1:6379> lrange mylist 1 3
1) "redis"
2) "b"
3) "a"

从右到左 获取列表的第 1 到第 3 个元素,可以执行如下操作

127.0.0.1:6379> lrange mylist -3 -1
1) "redis"
2) "b"
3) "a"
127.0.0.1:6379>

获取列表指定索引下标的元素

lindex key index

例如当前列表 最后一个 元素为 a

127.0.0.1:6379> lindex mylist -1
"a"
127.0.0.1:6379>

获取列表长度

llen key

例如,下面示例 当前列表长度 为 4

127.0.0.1:6379> llen mylist
(integer) 4
127.0.0.1:6379>

删除命令

从列表左侧弹出元素

lpop key

如下操作将 列表 最左侧的元素 c 弹出,弹出后 列表 变为 redis、b、a

127.0.0.1:6379> lpop mylist
"c"
127.0.0.1:6379> lrange mylist 0 -1
1) "redis"
2) "b"
3) "a"
127.0.0.1:6379>

从列表右侧弹出元素

rpop key

它的使用方法和 lpop 是一样的,只不过从列表 右侧 弹出元元素

127.0.0.1:6379> lpop mylist
"redis"
127.0.0.1:6379> lrange mylist 0 -1
1) "b"
2) "a"
127.0.0.1:6379>

删除指定元素

lrem key count value

lrem 命令会从 列表 中找到 等于 value 的元素进行 删除,根据 count 的不同分为三种情况

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

例如向列表 从左向右 插入 5 个 a,那么当前 列表 变为 “a a a a a b a”,下面操作将从列表 左边 开始删除 4 个为 a 的元素:

127.0.0.1:6379> rpush mylist a a a a a
(integer) 7
127.0.0.1:6379> lrem mylist 4 a
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "b"
2) "a"
3) "a"
127.0.0.1:6379>

按照索引范围修剪列表

127.0.0.1:6379> ltrim mylist 1 3
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "a"
127.0.0.1:6379>

修改命令

修改指定索引下标的元素

修改 指定索引下标 的元素

lset key index newValue

下面操作会将列表 mylist 中的第 2 个元素设置为 mysql:

127.0.0.1:6379> lset mylist 1 mysql
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "mysql"
127.0.0.1:6379>

其他操作命令

有关 列表 的 基础命令 已经介绍完了,下表是相关命令的 时间复杂度


内部编码

列表类型的 内部编码 有两种

ziplist(压缩列表)

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


linkedlist(链表)

当 列表类型 无法满足 ziplist 的条件时, Redis 会使用 linkedlist 作为 列表 的 内部实现。


应用场景

消息队列

通过 Redis 的 lpush + brpop 命令组合,即可实现 阻塞队列。如图所示:


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


文章列表

每个 用户 有属于自己的 文章列表,现需要 分页 展示文章列表。此时可以考虑使用 列表,因为列表不但是 有序的,同时支持 按照索引范围 获取元素。

每篇文章使用 哈希结构 存储,例如每篇文章有 3 个属性 title、timestamp、content:

hmset acticle:1 title xx timestamp 1476536196 content xxxx
hmset acticle:2 title yy timestamp 1476536196 content yyyy
...
hmset acticle:k title kk timestamp 1476512536 content kkkk

向用户文章列表 添加文章,user:{id}:articles 作为用户文章列表的 键:

lpush user:1:acticles article:1 article:3 article:5
lpush user:2:acticles article:2 article:4 article:6
...
lpush user:k:acticles article:7 article:8

分页 获取 用户文章列表,例如下面 伪代码 获取用户 id=1 的前 10 篇文章:

articles = lrange user:1:articles 0 9
for article in {articles}hgetall {article}

使用 列表 类型 保存 和 获取 文章列表会存在两个问题

第一:如果每次 分页 获取的 文章个数较多,需要执行多次 hgetall 操作,此时可以考虑使用 Pipeline 进行 批量获取,或者考虑将文章数据 序列化为字符串 类型,使用 mget 批量获取。

第二:分页 获取 文章列表 时, lrange 命令在列表 两端性能较好,但是如果 列表较大,获取列表 中间范围 的元素 性能会变差。此时可以考虑将列表做 二级拆分,或者使用 Redis 3.2 的 quicklist 内部编码实现,它结合 ziplist 和 linkedlist 的特点,获取列表 中间范围 的元素时也可以 高效完成。


其他场景

实际上列表的使用场景很多,具体可以参考如下

命令组合 对应数据结构
lpush + lpop Stack(栈)
lpush + rpop Queue(队列)
lpush + ltrim Capped Collection(有限集合)
lpush + brpop Message Queue(消息队列)

本文小结

本文详细介绍了Redis中的列表这种数据结构。

Redis数据结构之列表相关推荐

  1. 深入剖析Redis系列(七) - Redis数据结构之列表

    前言 列表(list)类型是用来存储多个 有序 的 字符串.在 Redis 中,可以对列表的 两端 进行 插入(push)和 弹出(pop)操作,还可以获取 指定范围 的 元素列表.获取 指定索引下标 ...

  2. 深入剖析Redis系列(五) - Redis数据结构之字符串

    前言 字符串类型 是 Redis 最基础的数据结构.字符串类型 的值实际可以是 字符串(简单 和 复杂 的字符串,例如 JSON.XML).数字(整数.浮点数),甚至是 二进制(图片.音频.视频),但 ...

  3. redis 底层数据结构 压缩列表 ziplist

    压缩列表是列表键和哈希键的底层实现之一.当一个列表键只包含少量列表项,并且每个列表项要么就是小整数,要么就是长度比较短的字符串,redis就会使用压缩列表来做列表键的底层实现 当一个哈希键只包含少量键 ...

  4. 在列表前方插入一个数据_通俗易懂的Redis数据结构基础教程

    Redis有5个基本数据结构,string.list.hash.set和zset.它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了. ...

  5. 「Redis数据结构」压缩列表(ZipList)

    「Redis数据结构」压缩列表(ZipList) 文章目录 「Redis数据结构」压缩列表(ZipList) 一.概述 二.结构 三.连锁更新问题 四.压缩列表的缺陷 五.小结 参考 ZipList ...

  6. Redis 数据结构-字典源码分析

    2019独角兽企业重金招聘Python工程师标准>>> 相关文章 Redis 初探-安装与使用 Redis 数据结构-字符串源码分析 本文将从以下几个方面介绍 前言 字典结构图 字典 ...

  7. 为了拿捏 Redis 数据结构,我画了 40 张图

    Redis 为什么那么快? 除了它是内存数据库,使得所有的操作都在内存上进行之外,还有一个重要因素,它实现的数据结构,使得我们对数据进行增删查改操作时,Redis 能高效的处理. 因此,这次我们就来好 ...

  8. 【带你重拾Redis】Redis数据结构及使用场景

    Redis数据结构 Redis有着非常丰富的数据结构,这些数据结构可以满足非常多的应用场景, 如果对这些数据结构有一个比较清晰的认知,使用Redis也会更加得心应手. Redis主要支持以下数据结构: ...

  9. redis 自减命令_Redis 实战 —— 04. Redis 数据结构常用命令简介

    字符串 P39 Redis 的字符串是一个有字节组成的序列,可以存储以下 3 种类型的值:字节串(byte string).整数.浮点数. 在需要的时候, Redis 会将整数转换成浮点数.整数的取值 ...

最新文章

  1. Android socket 编程 实现消息推送
  2. IB纪录(十七):At the heard of the image
  3. BZOJ 4898 Luogu P3778 [APIO2017]商旅 (分数规划、最短路)
  4. LiveVideoStackCon 2020 漫游指南
  5. this.counter$ = store.select(fromExample.getCounterCounter);
  6. 计算机网络教程三次握手,计算机网络(二) TCP协议的三次握手
  7. 软件工程第一次作业2018
  8. 星载计算机西北工业大学,星载计算机SRAM加固可靠性的研究与设计
  9. java客户端实验_java实验(客户端) 2015106宋世超
  10. keras指定gpu_keras实现多GPU或指定GPU的使用介绍
  11. opencv 识别微信登录验证滑动块位置
  12. 安卓(Android) 刷机教程(任何机型、小米、华为等等)
  13. 国外广告联盟前期需要准备的事情
  14. 【Swing】图片查看器
  15. 大数据挖掘的意义是什么?
  16. 智源社区AI周刊No.101:DeepMind推出AlphaTensor登Nature封面;stateof.ai发布AI情况报告...
  17. bootrom是什么?
  18. iOS-OC-3DES加密和解密
  19. 哪位神犇可以帮忙啊。
  20. 临时邮箱如何申请注册,申请临时邮箱后有什么好处?

热门文章

  1. Microsoft Visual Studio 2008从试用版转为正式版
  2. k8s与监控--解读prometheus监控kubernetes的配置文件
  3. 「旁门右道」CURL持久连接技巧
  4. leetCode 6. ZigZag Conversion 字符串 (上传费劲)
  5. 程维谈智慧交通:我们赶上好时代 走出了自己路
  6. Java的位运算符——与()、非(~)、或(|)、异或(^)
  7. 光纤通道(FC: Fibre Channel)
  8. Windows中命令提示符被禁用的解决方法
  9. fail-fast与fail-safe工作机制
  10. 在使用 Elasticsearch 时要注意什么?