跳到主要内容

Redis 列表(List)

1. 简介​

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。列表最多可存储 2^32 - 1 个元素。

2. 基本命令​

命令描述示例
LPUSH key element [element ...]从左端(头部)插入元素LPUSH book_list Java设计模式 Java并发编程
RPUSH key element [element ...]从右端(尾部)插入元素RPUSH book_list Python程序设计
LPUSHX key value将一个值插入到已存在的列表头部LPUSHX book_list "Python Cookbook"
RPUSHX key value为已存在的列表添加值RPUSHX book_list "C++语言程序设计"
LPOP key从左端(头部)弹出元素LPOP book_list
RPOP key从右端(尾部)弹出元素RPOP book_list
LLEN key获取列表长度LLEN book_list
LINDEX key index获取指定索引的元素LINDEX book_list 1
LSET key index element设置指定索引的元素值LSET book_list 1 "数据库程序设计"

2.1 示例​

127.0.0.1:6379> LPUSH book_list "Java设计模式" "Java并发编程"
(integer) 2
127.0.0.1:6379> RPUSH book_list "Python程序设计"
(integer) 3
127.0.0.1:6379> LPUSHX book_list "Python Cookbook"
(integer) 4
127.0.0.1:6379> LLEN book_list
(integer) 4
127.0.0.1:6379> LINDEX book_list 1
"Java设计模式"
127.0.0.1:6379> LSET book_list 1 "数据库程序设计"
OK
127.0.0.1:6379> LPOP book_list
"Python Cookbook"
127.0.0.1:6379> RPOP book_list
"Python程序设计"

3. 阻塞操作命令​

当列表为空时,阻塞等待新元素的命令:

命令描述示例
BLPOP key [key ...] timeout阻塞式左端弹出, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止BLPOP book_list 1000
BRPOP key [key ...] timeout阻塞式右端弹出, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止BRPOP book_list 1000
BRPOPLPUSH source destination timeout阻塞式弹出并推入另一个列表,将弹出的元素插入到另外一个列表中并返回它;
如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOPLPUSH book_list book_list1 500

3.1 示例​

# 列表为空时阻塞等待,直到新元素到达
127.0.0.1:6379> BLPOP book_list 1000

# 阻塞式右端弹出
127.0.0.1:6379> BRPOP book_list 1000

# 弹出并推入另一个列表(备份)
127.0.0.1:6379> BRPOPLPUSH book_list book_list1 500

4. 范围操作命令​

对列表指定范围内的元素进行操作:

命令描述说明
LRANGE key start stop获取指定范围的元素LRANGE book_list 0 2
LTRIM key start stop对一个列表进行修剪(trim),
让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
LTRIM book_list 0 1
`LINSERT key BEFOREAFTER pivot element`在指定元素前/后插入
LREM key count element删除指定数量的元素LREM book_list 1 "数据结构"

4.1 示例​

# 获取前 3 个元素
127.0.0.1:6379> LRANGE book_list 0 2
1) "Java并发编程"
2) "Java设计模式"
3) "数据库程序设计"

# 修剪列表,只保留前两个元素
127.0.0.1:6379> LTRIM book_list 0 1

# 在指定元素前插入
127.0.0.1:6379> LINSERT book_list BEFORE "Java设计模式" "C++ Primer"
(integer) 3

# 删除指定数量的元素
127.0.0.1:6379> LREM book_list 1 "Java并发编程"
(integer) 1

5. 列表间操作​

在不同列表之间移动元素:

命令描述示例
RPOPLPUSH source destination移除列表的最后一个元素,并将该元素添加到另一个列表并返回RPOPLPUSH book_list book_list1

5.1 示例​

127.0.0.1:6379> RPUSH book_list "C++ Primer"
(integer) 1
# 把 book_list 的最后一个元素移动到 book_list1
127.0.0.1:6379> RPOPLPUSH book_list book_list1
"C++ Primer"

6. 实际应用场景​

6.1 消息队列​

使用列表实现简单的消息队列系统:

# 生产者发送消息
LPUSH order_queue "{\"id\": 1, \"buyer\": \"张三\", \"price\": \"100\"}"
LPUSH order_queue "{\"id\": 1, \"buyer\": \"李四\", \"price\": \"500\"}"

# 消费者处理消息
# 阻塞等待消息
BRPOP order_queue 30

# 可靠队列(弹出前先转移到备份队列)
BRPOPLPUSH order_queue completed_queue 30

# 处理完成后,按消息内容从备份队列移除该条记录
LREM completed_queue 1 "completed"

# 失败重试
RPOPLPUSH processing_queue refund_queue

6.2 最新动态​

存储用户的最新动态或文章列表:

# 发布新动态
LPUSH user:1001:timeline "{\"id\": 101, \"content\": \"今天天气不错\", \"time\": 1609459200}"
LPUSH user:1001:timeline "{\"id\": 102, \"content\": \"学习Redis\", \"time\": 1609462800}"

# 获取最新10条动态
LRANGE user:1001:timeline 0 9

# 限制动态数量(只保留最新100条)
LTRIM user:1001:timeline 0 99

# 获取特定动态
LINDEX user:1001:timeline 0 # 最新动态
LINDEX user:1001:timeline -1 # 最早动态

6.3 任务调度​

实现任务调度和处理流程:

# 任务提交
LPUSH task:pending "{\"id\": 1, \"type\": \"image_process\", \"file\": \"image1.jpg\"}"
LPUSH task:pending "{\"id\": 2, \"type\": \"video_encode\", \"file\": \"video1.mp4\"}"

# 工作进程获取任务
BRPOPLPUSH task:pending task:processing 30

# 任务完成
RPOPLPUSH task:processing task:completed

# 任务失败
RPOPLPUSH task:processing task:failed

# 重试失败任务
RPOPLPUSH task:failed task:pending

# 监控队列状态
LLEN task:pending # 待处理任务数
LLEN task:processing # 处理中任务数
LLEN task:completed # 已完成任务数
LLEN task:failed # 失败任务数

7. 性能优化建议​

  • 避免大列表: 单个列表元素数量不宜过多(建议小于 10 万)
  • 使用阻塞操作: 在队列场景中使用 BLPOP/BRPOP 避免轮询
  • 批量操作: 使用 LPUSH/RPUSH 的多元素版本减少网络往返
  • 合理使用索引: 避免频繁使用 LINDEX 访问中间元素
  • 定期清理: 使用 LTRIM 限制列表大小
  • 选择合适的端: 根据业务需求选择从左端还是右端操作

8. 列表 vs 其他数据类型​

8.1 数据类型选择建议​

  • List vs Set: List 允许重复元素且有序,Set 不允许重复且无序
  • List vs Sorted Set: List 按插入顺序排序,Sorted Set 按分数排序
  • List vs Stream: Stream 更适合复杂的消息队列场景
  • 使用 List 的场景: 消息队列、最新动态、简单排行榜、任务调度