列表(list)类型是用来存储多个有序的字符串,列表中的每个字符串称为元素(element),一个列表最多可以存储232-1个元素。在Redis中,可以对列表两端插入(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。

列表类型有两个特点:

  1. 列表中的元素是有序的,这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表。
  2. 列表中的元素可以是重复的.

一、内部实现

在Redis3.2版本以前列表类型的内部编码有两种。

  • ziplist(压缩列表):当列表的元素个数小于list-max-ziplist-entries配置(默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置时(默认64字节),Redis会选用ziplist来作为列表的内部实现来减少内存的使用。
  • linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会使用linkedlist作为列表的内部实现。

而在Redis3.2版本开始对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist.

关于这三种底层数据结构可以查看我的另外三篇文章

Redis数据结构——链表

Redis数据结构——压缩列表

Redis数据结构——quicklist

二、常用命令

Redis列表对象常用命令如下表(点击命令可查看命令详细说明)。

命令 说明 时间复杂度
BLPOP key [key ...] timeout 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用 O(1)
BRPOP key [key ...] timeout 删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用 O(1)
BRPOPLPUSH source destination timeout 弹出一个列表的值,将它推到另一个列表,并返回它;或阻塞,直到有一个可用 O(1)
LINDEX key index 获取一个元素,通过其索引列表 O(N)
LINSERT key BEFORE AFTER pivot value在列表中的另一个元素之前或之后插入一个元素 O(N)
LLEN key 获得队列(List)的长度 O(1)
LPOP key 从队列的左边出队一个元素 O(1)
LPUSH key value [value ...] 从队列的左边入队一个或多个元素 O(1)
LPUSHX key value 当队列存在时,从队到左边入队一个元素 O(1)
LRANGE key start stop 从列表中获取指定返回的元素 O(S+N)
LREM key count value 从列表中删除元素 O(N)
LSET key index value 设置队列里面一个元素的值 O(N)
LTRIM key start stop 修剪到指定范围内的清单 O(N)
RPOP key 从队列的右边出队一个元 O(1)
RPOPLPUSH source destination 删除列表中的最后一个元素,将其追加到另一个列表 O(1)
RPUSH key value [value ...] 从队列的右边入队一个元素 O(1)
RPUSHX key value 从队列的右边入队一个元素,仅队列存在时有效 O(1)

三、使用场景

3.1 消息队列

列表类型可以使用 rpush 实现先进先出的功能,同时又可以使用 lpop 轻松的弹出(查询并删除)第一个元素,所以列表类型可以用来实现消息队列

3.2 文章(商品等)列表

我们以博客站点为例,当用户和文章都越来越多时,为了加快程序的响应速度,我们可以把用户自己的文章存入到 List 中,因为 List 是有序的结构,所以这样又可以完美的实现分页功能,从而加速了程序的响应速度。

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

    hmset acticle:1 title xx timestamp 1476536196 content xxxx
    ...
    hmset acticle:k title yy timestamp 1476512536 content yyyy
    ...
  2. 向用户文章列表添加文章,user:{id}:articles作为用户文章列表的键:

    lpush user:1:acticles article:1 article3
    ...
    lpush
    ...
  3. 分页获取用户文章列表,例如下面伪代码获取用户id=1的前10篇文章

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

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

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

关于列表的使用场景可参考以下几个命令组合:

  • lpush+lpop=Stack(栈)
  • lpush+rpop=Queue(队列)
  • lpush+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息队列)

小结

本篇文章我们总结了Redis 列表对象的内部实现、常用命令以及常用的一些场景,那么大家在项目中对Redis列表对象的使用都有哪些场景呢,欢迎在评论区给我留言和分享,我会第一时间反馈!我们共同学习与进步!

参考

《Redis设计与实现》

《Redis开发与运维》

《Redis官方文档》

-----END-----

Redis对象——列表(List)的更多相关文章

  1. 【redis源码阅读】redis对象

    结构定义 在redis中,对象的数据结构定义如下: ​typedef struct redisObject { ​unsigned type:4; ​unsgined encoding:4; ​uns ...

  2. Redis对象类型

    Redis对象类型 Redis基于基础的数据结构创建的对象: 字符串对象. 列表对象. 哈希对象. 集合对象 有序集合对象. 对象回收:Redis对象系统实现了基于引用计数技术的内存回收机制,当程序不 ...

  3. Redis底层探秘(五):Redis对象

    前面几篇文章,我们一起学习了redis用到的所有主要数据结构,比如简单动态字符串(sds).双端链表.字典.压缩列表.整数集合等等. redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这 ...

  4. 【redis对象,集合序列化Demo】

    package org.seckill.dao.cache; import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStr ...

  5. Redis对象的设计与实现

    一.Redis对象结构Redis中的每个对象都由一个redisObject结构表示: typedef struct redisObject { unsigned type;//类型 unsigned ...

  6. 面试官:你了解过Redis对象底层实现吗

    上一章我们讲了Redis的底层数据结构,不了解的人可能会有疑问:这个和平时用的五大对象有啥关系呢?这一章我们就主要解释他们所建立的联系. 看这个文件之前,如果对ziplist.skiplist.int ...

  7. Redis之对象篇——Redis对象系统简介

    Redis之对象篇--Redis对象系统简介 前言     之前几篇文章,简单介绍 Redis用到的所有主要数据结构,简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合.跳跃表. 图解Red ...

  8. Redis对象

    概述 Redis并没有使用基础数据结构去实现键值数据库,而是基于数据结构封装了一个个对象. 类型和编码 由于Redis是键值数据库,所以每次存储数据时,至少包含两个对象,即K.V对应的对象.其数据结构 ...

  9. spring jdbc 查询结果返回对象、对象列表

    首先,需要了解spring jdbc查询时,有三种回调方式来处理查询的结果集.可以参考 使用spring的JdbcTemplate进行查询的三种回调方式的比较,写得还不错. 1.返回对象(queryF ...

随机推荐

  1. docker 搭建本地私有仓库

    1.使用registry镜像创建私有仓库 安装docker后,可以通过官方提供的 registry 镜像来简单搭建一套本地私有仓库环境: docker run -d -p : registry: 这将 ...

  2. 第四章、深入理解vue组件

    4-1.使用组件的细节 a.使用is解决html出现bug 如下 table下面应该为tr,所以页面渲染的时候没有找到tr是有问题的,所以是有小bug,所以table中必须是tr b.改上面bug,t ...

  3. 智慧港口——基于二三维一体化GIS的港口可视化监管平台

    “智慧港口”是以现代化基础设施设备为基础,以云计算.大数据.物联网.移动互联网.智能控制等新一代信息技术与港口运输业务深度融合为核心,以港口运输组织服务创新为动力,以完善的体制机制.法律法规.标准规范 ...

  4. 2020年ubuntu sever1804 安装和配置

    最后一次折腾linux服务器,应该是13的我的VPS.因为转行后,没有及时关注vps续费的问题,结果过期,所有的数据丢失了 当时觉得,反正都不做了,丢了就丢了吧,可现在想起来,实在是太后悔了. 今天, ...

  5. php 防注入

    a. 打开magic_quotes_gpc或使用addslashes()函数 当php.ini里的 magic_quotes_gpc 为On 时. 提交的变量中所有的 ' (单引号), "  ...

  6. requests.exceptions.SSLError报错

    requests.exceptions.SSLError: HTTPSConnectionPool(host='www.baidu.com', port=443): Max retries excee ...

  7. kafka实现无消息丢失与精确一次语义(exactly once)处理

    在很多的流处理框架的介绍中,都会说kafka是一个可靠的数据源,并且推荐使用Kafka当作数据源来进行使用.这是因为与其他消息引擎系统相比,kafka提供了可靠的数据保存及备份机制.并且通过消费者位移 ...

  8. java输入输出流操作同一资源实现覆盖引发冲突的解析

    一.问题发生的场景 题目:把s.txt中大写转成小写,小写转成大写,空格转成下划线,在输入到文件中覆盖之前的 前面的没有问题,问题出现在后面的覆盖文件上,输入流.输出流要操作同一个文件的问题 二.小白 ...

  9. MyBatis框架——单表查询

    Mybatis单表查询,示例 1.创建数据库 /* Navicat MySQL Data Transfer Source Server : localhost Source Server Versio ...

  10. iOS开发:十六进制颜色转UIColor

    Objective-C UIColor * __nullable UIColorFromHexValue(NSUInteger hexValue) { CGFloat red = (hexValue ...