Redis List 类型
1. List 类型概述
Section titled “1. List 类型概述”List 是 Redis 中的有序、可重复的字符串列表,底层是双端链表结构,支持从两端高效插入和弹出,时间复杂度 O(1)。
List 结构示意(双端队列):
key = "msg:queue"
LEFT ←── [msg5] [msg4] [msg3] [msg2] [msg1] ──→ RIGHT ↑ ↑ LPUSH/LPOP RPUSH/RPOP| 特点 | 说明 |
|---|---|
| 有序 | 元素按插入顺序存储,支持按索引访问 |
| 可重复 | 允许存储相同元素 |
| 双端操作 | 头部和尾部均支持 O(1) 插入/弹出 |
| 阻塞弹出 | BLPOP 支持阻塞等待,适合消息队列 |
| 上限 | 单个 List 最多 2^32 - 1 个元素 |
2. 常用命令
Section titled “2. 常用命令”2.1. 插入与弹出
Section titled “2.1. 插入与弹出”# 插入LPUSH list a b c # 从左插入,最终顺序:c b a(后插的在左边)RPUSH list d e # 从右插入,最终顺序:c b a d eLINSERT list BEFORE "a" "x" # 在元素 a 前插入 x
# 弹出LPOP list # 从左弹出,返回元素RPOP list # 从右弹出,返回元素LPOP list 2 # 从左弹出 2 个(Redis 6.2+)
# 阻塞弹出(消息队列核心命令)BLPOP list 10 # 阻塞等待,最多 10 秒,有消息立即返回BRPOP list 10 # 从右端阻塞弹出2.2. 查询
Section titled “2.2. 查询”LRANGE list 0 -1 # 获取全部元素(-1 表示最后一个)LRANGE list 0 4 # 获取前 5 个元素LINDEX list 0 # 获取指定下标元素(0 = 第一个,-1 = 最后一个)LLEN list # 获取列表长度2.3. 修改与删除
Section titled “2.3. 修改与删除”LSET list 0 "new" # 修改指定下标的值LREM list 2 "a" # 从左删除 2 个值为 "a" 的元素(负数从右删)LTRIM list 0 99 # 裁剪,只保留下标 0~99 的元素(常用于限制列表长度)2.4. 命令速查
Section titled “2.4. 命令速查”| 命令 | 说明 | 复杂度 |
|---|---|---|
LPUSH / RPUSH | 左/右插入 | O(1) |
LPOP / RPOP | 左/右弹出 | O(1) |
BLPOP / BRPOP | 阻塞弹出 | O(1) |
LRANGE key s e | 范围查询 | O(N) |
LINDEX key i | 下标查询 | O(N) |
LLEN key | 列表长度 | O(1) |
LREM key n val | 删除元素 | O(N) |
LTRIM key s e | 裁剪列表 | O(N) |
3. 底层编码
Section titled “3. 底层编码”List 底层编码├── listpack(紧凑列表)│ → 元素数 ≤ 128 且每个元素长度 ≤ 64 字节│ → 内存紧凑,连续存储│└── quicklist(快速列表) → 超过阈值后自动升级 → 由多个 listpack 节点组成的双向链表 → 兼顾内存效率与操作性能4. SpringBoot 实战
Section titled “4. SpringBoot 实战”4.1. 基础操作
Section titled “4.1. 基础操作”@Autowiredprivate StringRedisTemplate redisTemplate;
ListOperations<String, String> listOps = redisTemplate.opsForList();
// 插入listOps.leftPush("queue", "task1");listOps.rightPush("queue", "task2");listOps.rightPushAll("queue", List.of("task3", "task4"));
// 弹出String task = listOps.leftPop("queue");String taskWithTimeout = listOps.leftPop("queue", 5, TimeUnit.SECONDS); // 阻塞 5 秒
// 查询List<String> all = listOps.range("queue", 0, -1);String first = listOps.index("queue", 0);Long size = listOps.size("queue");
// 裁剪(保留最新 100 条)listOps.trim("news:latest", 0, 99);4.2. 简单消息队列
Section titled “4.2. 简单消息队列”@Service@RequiredArgsConstructorpublic class SimpleQueue {
private final StringRedisTemplate redisTemplate; private static final String QUEUE_KEY = "msg:queue";
// 生产者:推入消息 public void push(String message) { redisTemplate.opsForList().rightPush(QUEUE_KEY, message); }
// 消费者:阻塞拉取(无消息时等待,不轮询) public String pop() { return redisTemplate.opsForList() .leftPop(QUEUE_KEY, 10, TimeUnit.SECONDS); }}4.3. 最新动态列表(定长列表)
Section titled “4.3. 最新动态列表(定长列表)”@Service@RequiredArgsConstructorpublic class FeedService {
private final StringRedisTemplate redisTemplate; private static final int MAX_FEED_SIZE = 500;
// 发布动态:插入头部,保持最新在前 public void publish(Long userId, String content) { String key = "feed:" + userId; redisTemplate.opsForList().leftPush(key, content); // 只保留最新 500 条 redisTemplate.opsForList().trim(key, 0, MAX_FEED_SIZE - 1); }
// 分页获取动态 public List<String> getFeeds(Long userId, int page, int size) { String key = "feed:" + userId; long start = (long)(page - 1) * size; long end = start + size - 1; return redisTemplate.opsForList().range(key, start, end); }}5. 典型业务场景
Section titled “5. 典型业务场景”5.1. List 实现队列 vs 栈
Section titled “5.1. List 实现队列 vs 栈”队列(FIFO):RPUSH 入队 + LPOP 出队┌─────────────────────────────────┐│ RPUSH ──▶ [e][d][c][b][a] ◀── LPOP │└─────────────────────────────────┘
栈(LIFO):LPUSH 入栈 + LPOP 出栈┌─────────────────────────────────┐│ LPUSH ──▶ [c][b][a] ◀── LPOP │└─────────────────────────────────┘5.2. 场景选型速查
Section titled “5.2. 场景选型速查”| 场景 | 方案 | 关键命令 |
|---|---|---|
| 异步任务队列 | RPUSH 入队 + BLPOP 阻塞消费 | BLPOP |
| 最新消息列表 | LPUSH + LTRIM 限长 | LTRIM |
| 历史记录 | RPUSH + LRANGE 分页 | LRANGE |
| 操作日志栈 | LPUSH + LPOP 后进先出 | LPOP |