当前位置: 首页 > news >正文

Redis List 的详细介绍

Redis List 的详细介绍

以下是 Redis List 的详细介绍,从基础命令内部编码使用场景三个维度展开:


一、基础命令

Redis List 支持双向操作(头尾插入/删除),适用于队列、栈等场景,以下是核心命令分类:

1. 插入与删除
  • LPUSH / RPUSH:从左侧(头部)或右侧(尾部)插入元素。

    LPUSH mylist "A"        # 头部插入 "A",返回列表长度
    RPUSH mylist "B"        # 尾部插入 "B",返回列表长度
    
  • LPOP / RPOP:从头部或尾部移除并返回元素。

    LPOP mylist             # 移除头部元素 "A"
    RPOP mylist             # 移除尾部元素 "B"
    
  • LINSERT:在指定元素前/后插入新元素。

    LINSERT mylist BEFORE "B" "A"  # 在 "B" 前插入 "A"
    
  • LREM:删除指定数量的匹配元素。

    LREM mylist 2 "A"       # 删除最多2个 "A"
    
2. 查询与截断
  • LRANGE:获取指定索引范围内的元素。

    LRANGE mylist 0 -1      # 获取所有元素
    
  • LINDEX:获取指定位置的元素。

    LINDEX mylist 0         # 返回头部元素
    
  • LLEN:获取列表长度。

    LLEN mylist             # 返回列表元素总数
    
  • LTRIM:保留指定范围内的元素,其余删除。

    LTRIM mylist 0 4        # 仅保留前5个元素
    
3. 阻塞操作
  • BLPOP / BRPOP:阻塞式弹出元素,适用于消息队列。

    BLPOP task_queue 10     # 阻塞10秒等待头部元素
    

二、内部编码

Redis List 的底层实现根据数据规模动态选择编码方式:

1. listpack(Redis 7.0+)
  • 条件:当所有元素满足以下条件时使用 listpack(连续内存结构):

    • 元素数量 ≤ list-max-listpack-size​(默认 512)。
    • 每个元素的大小 ≤ list-max-listpack-value​(默认 64 字节)。
  • 特点

    • 内存紧凑,无指针开销,适合小规模数据。
    • 规避了 ziplist 的连锁更新问题(见 Redis 7.0+ 的改进)。
2. quicklist(Redis 3.2+)
  • 触发条件:超出 listpack 容量时自动切换。

  • 结构:由多个 listpack 节点组成的双向链表,平衡内存与操作效率。

    • 每个 listpack 节点存储多个元素。
    • 支持头尾快速插入/删除(时间复杂度 O(1))。
  • 配置调优

    list-max-listpack-size -2    # 默认每个 listpack 节点大小 8KB
    list-compress-depth 0        # 压缩深度(0 表示不压缩)
    

三、使用场景

1. 消息队列
  • 生产者LPUSH​ 插入任务到队列头部。

  • 消费者BRPOP​ 阻塞获取任务,避免轮询。

    # 生产者
    LPUSH task_queue "task1"
    # 消费者
    BRPOP task_queue 0          # 0 表示无限阻塞
    
2. 最新消息排行榜
  • 插入LPUSH​ 将新消息加入列表头部。

  • 展示LRANGE 0 9​ 获取最新的 10 条消息。

  • 清理LTRIM 0 99​ 保留最近 100 条消息。

    package com.example.redis.list;/*** 描述: 消息绑** @author ZHOUXIAOYUE* @date 2025/4/17 15:07*/
    import redis.clients.jedis.Jedis;
    import java.util.List;
    public class LatestNewsBoard {public static void main(String[] args) {// 连接 Redis 服务,默认地址 localhost 和端口 6379Jedis jedis = new Jedis("localhost", 6379);// 定义 Redis List 的 keyString listKey = "latest:news";for (int x= 0; x < 100; x++) {// 模拟插入一条新消息String newMessage = "Breaking News: Redis 使用场景持续扩展!"+x;// 使用 LPUSH 命令将消息插入到列表头部jedis.lpush(listKey, newMessage);System.out.println("新消息已插入: " + newMessage);}// 使用 LLEN 命令获取// 数据清理:使用 LTRIM 保留最近 100 条消息jedis.ltrim(listKey, 0, 99);System.out.println("消息列表已清理,保留最近 100 条记录。");// 展示最新 10 条消息:使用 LRANGE 命令获取列表中 0~9 范围内的消息List<String> latestMessages = jedis.lrange(listKey, 0, 9);System.out.println("最新的 10 条消息如下:");for (String message : latestMessages) {System.out.println(message);}// 关闭 Redis 连接jedis.close();}
    }
    
3. 历史记录
  • 用户操作日志:LPUSH​ 记录用户行为,LTRIM​ 限制记录数量。

    LPUSH user:1001:logs "click_button_A"
    LTRIM user:1001:logs 0 99   # 保留最近 100 条日志
    
4. 栈(LIFO)
  • 入栈:LPUSH​,出栈:LPOP​。

    LPUSH my_stack "data1"
    LPOP my_stack               # 返回 "data1"
    
5. 数据分片存储
  • 大列表拆分为多个 quicklist 节点,减少单节点内存压力。

四、性能与调优建议

  1. 优先使用 LPUSH/RPUSH+LTRIM​:

    • 实现固定长度列表(如最新 100 条消息),避免无限增长。
  2. 避免大范围 LRANGE操作

    • 获取全部数据时,使用 LRANGE 0 -1​ 可能导致阻塞,建议分页或迭代遍历。
  3. 合理配置 quicklist

    • 调整 list-max-listpack-size​ 平衡内存与性能(默认 8KB)。
    • 启用压缩(list-compress-depth​)节省内存,但会增加 CPU 开销。

总结

  • 核心优势:支持双向操作、阻塞弹出、动态分片存储。

  • 适用场景:消息队列、实时排行榜、操作日志、栈/队列实现。

  • 版本差异

    • Redis 3.2+ 使用 quicklist,替代旧版的 ziplist + linkedlist。
    • Redis 7.0+ 使用 listpack 替代 ziplist,提升安全性和性能。
  • 命令选择:高频写入用 LPUSH​/RPUSH​,阻塞消费用 BRPOP​,精确控制用 LTRIM​。


使用案例 :

  • 博客信息展示 列表

    Editor _ Mermaid Chart-2025-04-17-092414

    package com.example.redis.list;/*** 描述:** @author ZHOUXIAOYUE* 每篇文章使用哈希结构存储(字段:title、timestamp、content),文章的 key 格式为 "article:{id}"。* 每个用户有自己的文章列表,列表 key 格式为 "user:{id}:articles",列表中存储文章 id,利用 LPUSH 添加文章(最新的在列表头部)。* 分页获取用户文章列表,示例中获取用户 id=1 的前 10 篇文章(即列表索引 0~9),再根据文章 id 获取对应的文章详细信息。* @date 2025/4/17 16:35*/
    import redis.clients.jedis.Jedis;
    import java.util.Map;
    import java.util.HashMap;
    import java.util.List;
    import java.util.ArrayList;
    public class UserArticlesPagination {// 定义文章类static class Article {private String id;private String title;private String timestamp;private String content;public Article(String id, String title, String timestamp, String content) {this.id = id;this.title = title;this.timestamp = timestamp;this.content = content;}public String getId() {return id;}public String getTitle() {return title;}public String getTimestamp() {return timestamp;}public String getContent() {return content;}}// 添加文章,将文章哈希存储,并将文章 id 插入到用户的文章列表中public static void addArticle(Jedis jedis, String userId, Article article) {// 定义文章的 key 格式: article:{id}String articleKey = "article:" + article.getId();Map<String, String> articleMap = new HashMap<>();articleMap.put("title", article.getTitle());articleMap.put("timestamp", article.getTimestamp());articleMap.put("content", article.getContent());// 使用 HMSET 存储文章哈希jedis.hmset(articleKey, articleMap);// 将文章 id 添加到用户文章列表中,列表 key 格式: user:{id}:articlesString userArticlesKey = "user:" + userId + ":articles";// 使用 LPUSH 保证最新文章位于列表头部jedis.lpush(userArticlesKey, article.getId());}// 分页获取用户的文章列表,并返回文章详情集合public static List<Map<String, String>> getUserArticles(Jedis jedis, String userId, int page, int pageSize) {String userArticlesKey = "user:" + userId + ":articles";// 计算起始和结束索引(分页从 1 开始)int start = (page - 1) * pageSize;int end = start + pageSize - 1;// 获取文章 id 列表List<String> articleIds = jedis.lrange(userArticlesKey, start, end);List<Map<String, String>> articles = new ArrayList<>();// 根据文章 id 获取文章详情for (String articleId : articleIds) {String articleKey = "article:" + articleId;Map<String, String> articleData = jedis.hgetAll(articleKey);// 如果文章数据存在,则加入结果列表if (!articleData.isEmpty()) {articles.add(articleData);}}return articles;}public static void main(String[] args) {// 连接 Redis 服务,默认地址 localhost 与端口 6379Jedis jedis = new Jedis("localhost", 6379);// 假设用户 id 为 "1",添加几篇文章测试String userId = "1";Article article1 = new Article("101", "Redis 入门", "2023-10-01 10:00:00", "Redis 是一个键值存储系统...");Article article2 = new Article("102", "Redis 高级特性", "2023-10-02 11:30:00", "Redis 支持多种数据结构...");Article article3 = new Article("103", "Redis 实战案例", "2023-10-03 14:20:00", "通过案例来掌握 Redis 应用...");addArticle(jedis, userId, article1);addArticle(jedis, userId, article2);addArticle(jedis, userId, article3);// 分页获取用户文章列表:获取第一页,页面大小为 10List<Map<String, String>> articles = getUserArticles(jedis, userId, 1, 10);System.out.println("用户 " + userId + " 的文章列表:");for (Map<String, String> articleData : articles) {System.out.println("标题:" + articleData.get("title") + ", 时间:" + articleData.get("timestamp"));System.out.println("内容:" + articleData.get("content"));System.out.println("--------------------------");}// 关闭 Jedis 连接jedis.close();}
    }
    

http://www.xdnf.cn/news/1801.html

相关文章:

  • 方德桌面操作系统V5.0-G23 vim无法复制粘贴内容
  • Java虚拟机(JVM)平台无关?相关?
  • 在Linux下安装Gitlab
  • 2.深入剖析 Rust+Axum 类型安全路由系统
  • 极狐GitLab GEO 功能介绍
  • DAY 47 leetcode 232--栈与队列.用栈实现队列
  • vue3 element-plus中的国际化在onMounted中的写法
  • docker Windows 存放位置
  • 【web考试系统的设计】
  • 零服务器免备案!用Gitee代理+GitHub Pages搭建个人博客:绕过443端口封锁实战记录
  • 基于Flask的漏洞挖掘知识库系统设计与实现
  • 对抗生成进化:基于DNA算法的AIGC检测绕过——让AI创作真正“隐形“
  • 生物信息学技能树(Bioinformatics)与学习路径
  • 04-libVLC的视频播放器:获取媒体信息
  • 【裁员感想】
  • 关于webpack的知识点
  • 《似锦》:画饼之—你画给我我画给你
  • java 设计模式之代理模式
  • Android Compose Activity 页面跳转动画详解
  • 【Leetcode 每日一题】2176. 统计数组中相等且可以被整除的数对
  • ubuntu磁盘挂载
  • MySQL GTID集合运算函数总结
  • e实例性能测评:Intel Xeon Platinum处理器,经济型入门级服务器
  • Java设计开发商城抢票功能
  • Sql刷题日志(day3)
  • 代码随想录算法训练营第二十天
  • 关于C语言的模拟物理模型
  • vue3 el-dialog新增弹窗,不希望一进去就校验名称没有填写
  • SQL刷题记录贴
  • Oracle测试题目及笔记(单选)