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:获取指定位置的元素。
- LLEN:获取列表长度。
- 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 和端口 6379
- Jedis jedis = new Jedis("localhost", 6379);
- // 定义 Redis List 的 key
- String 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 节点,淘汰单节点内存压力。
四、性能与调优建议
- 优先利用 LPUSH /RPUSH +LTRIM:
- 实现固定长度列表(如最新 100 条消息),克制无穷增长。
- 克制大范围 LRANGE 利用:
- 获取全部数据时,利用 LRANGE 0 -1 大概导致阻塞,建议分页或迭代遍历。
- 公道设置 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。
利用案例 :
- 博客信息展示 列表
 - 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}:articles
- String 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 与端口 6379
- Jedis 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);
- // 分页获取用户文章列表:获取第一页,页面大小为 10
- List<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();
- }
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|