LPUSH、RPUSH、LPOP、RPOP、LRANGE、LINDEX等
List是Redis中的有序字符串列表,按照插入顺序排序。它是一个双向链表结构,支持在头部和尾部进行高效的插入和删除操作。List最多可以包含2^32-1个元素(超过40亿个)。
Redis的List底层使用两种数据结构:
# LPUSH: 从列表左侧(头部)插入元素
127.0.0.1:6379> LPUSH mylist "world"
(integer) 1
127.0.0.1:6379> LPUSH mylist "hello"
(integer) 2
# 结果: ["hello", "world"]
# RPUSH: 从列表右侧(尾部)插入元素
127.0.0.1:6379> RPUSH mylist "!"
(integer) 3
# 结果: ["hello", "world", "!"]
# 一次插入多个元素
127.0.0.1:6379> LPUSH numbers 3 2 1
(integer) 3
# 结果: [1, 2, 3](注意插入顺序)
127.0.0.1:6379> RPUSH letters a b c d
(integer) 4
# 结果: ["a", "b", "c", "d"]
# LPUSHX/RPUSHX: 仅当列表存在时才插入
127.0.0.1:6379> LPUSHX newlist "value"
(integer) 0 # 列表不存在,插入失败
127.0.0.1:6379> LPUSH newlist "first"
(integer) 1
127.0.0.1:6379> LPUSHX newlist "second"
(integer) 2 # 列表存在,插入成功
# LINSERT: 在指定元素前或后插入新元素
127.0.0.1:6379> RPUSH fruits "apple" "banana" "orange"
(integer) 3
# 在"banana"前插入"grape"
127.0.0.1:6379> LINSERT fruits BEFORE "banana" "grape"
(integer) 4
# 结果: ["apple", "grape", "banana", "orange"]
# 在"banana"后插入"mango"
127.0.0.1:6379> LINSERT fruits AFTER "banana" "mango"
(integer) 5
# 结果: ["apple", "grape", "banana", "mango", "orange"]
# 如果指定元素不存在,返回-1
127.0.0.1:6379> LINSERT fruits BEFORE "watermelon" "kiwi"
(integer) -1
# LPOP: 从列表左侧(头部)弹出元素
127.0.0.1:6379> RPUSH queue "task1" "task2" "task3"
(integer) 3
127.0.0.1:6379> LPOP queue
"task1"
127.0.0.1:6379> LPOP queue
"task2"
# RPOP: 从列表右侧(尾部)弹出元素
127.0.0.1:6379> RPOP queue
"task3"
# 列表为空时返回nil
127.0.0.1:6379> LPOP queue
(nil)
# Redis 6.2+支持一次弹出多个元素
127.0.0.1:6379> RPUSH numbers 1 2 3 4 5
(integer) 5
127.0.0.1:6379> LPOP numbers 2
1) "1"
2) "2"
127.0.0.1:6379> RPOP numbers 2
1) "5"
2) "4"
# LREM: 删除指定数量的指定元素
# LREM key count value
# count > 0: 从头到尾删除count个value
# count < 0: 从尾到头删除|count|个value
# count = 0: 删除所有value
127.0.0.1:6379> RPUSH items "a" "b" "a" "c" "a" "d" "a"
(integer) 7
# 从头删除2个"a"
127.0.0.1:6379> LREM items 2 "a"
(integer) 2
# 结果: ["b", "c", "a", "d", "a"]
# 从尾删除1个"a"
127.0.0.1:6379> LREM items -1 "a"
(integer) 1
# 结果: ["b", "c", "a", "d"]
# 删除所有"a"
127.0.0.1:6379> RPUSH items "a" "a"
(integer) 6
127.0.0.1:6379> LREM items 0 "a"
(integer) 3
# 结果: ["b", "c", "d"]
# LTRIM: 保留指定范围的元素,删除其他元素
127.0.0.1:6379> RPUSH logs "log1" "log2" "log3" "log4" "log5" "log6"
(integer) 6
# 保留索引1到3的元素
127.0.0.1:6379> LTRIM logs 1 3
OK
127.0.0.1:6379> LRANGE logs 0 -1
1) "log2"
2) "log3"
3) "log4"
# 保留最新的3条日志
127.0.0.1:6379> RPUSH logs "log5" "log6" "log7"
(integer) 6
127.0.0.1:6379> LTRIM logs -3 -1
OK
127.0.0.1:6379> LRANGE logs 0 -1
1) "log5"
2) "log6"
3) "log7"
# LRANGE: 获取指定范围的元素
127.0.0.1:6379> RPUSH numbers 1 2 3 4 5 6 7 8 9 10
(integer) 10
# 获取前3个元素
127.0.0.1:6379> LRANGE numbers 0 2
1) "1"
2) "2"
3) "3"
# 获取所有元素
127.0.0.1:6379> LRANGE numbers 0 -1
1) "1"
2) "2"
...
10) "10"
# 获取最后3个元素
127.0.0.1:6379> LRANGE numbers -3 -1
1) "8"
2) "9"
3) "10"
# 分页查询(每页5条)
# 第1页
127.0.0.1:6379> LRANGE numbers 0 4
# 第2页
127.0.0.1:6379> LRANGE numbers 5 9
# LINDEX: 获取指定索引的元素
127.0.0.1:6379> RPUSH colors "red" "green" "blue" "yellow"
(integer) 4
127.0.0.1:6379> LINDEX colors 0
"red"
127.0.0.1:6379> LINDEX colors 2
"blue"
127.0.0.1:6379> LINDEX colors -1
"yellow" # 最后一个元素
127.0.0.1:6379> LINDEX colors -2
"blue" # 倒数第二个元素
# 索引超出范围返回nil
127.0.0.1:6379> LINDEX colors 10
(nil)
# LLEN: 获取列表长度
127.0.0.1:6379> LLEN colors
(integer) 4
# 列表不存在时返回0
127.0.0.1:6379> LLEN nonexist
(integer) 0
# LSET: 设置指定索引的元素值
127.0.0.1:6379> RPUSH animals "cat" "dog" "bird"
(integer) 3
127.0.0.1:6379> LSET animals 1 "rabbit"
OK
127.0.0.1:6379> LRANGE animals 0 -1
1) "cat"
2) "rabbit"
3) "bird"
# 使用负数索引
127.0.0.1:6379> LSET animals -1 "fish"
OK
127.0.0.1:6379> LRANGE animals 0 -1
1) "cat"
2) "rabbit"
3) "fish"
# 索引超出范围会报错
127.0.0.1:6379> LSET animals 10 "value"
(error) ERR index out of range
# BLPOP/BRPOP: 阻塞式弹出元素
# 如果列表为空,会阻塞等待,直到有元素或超时
# 终端1: 阻塞等待(超时时间10秒)
127.0.0.1:6379> BLPOP queue 10
# 阻塞中...
# 终端2: 插入元素
127.0.0.1:6379> RPUSH queue "task1"
(integer) 1
# 终端1: 立即返回
1) "queue" # 键名
2) "task1" # 弹出的元素
# 超时返回nil
127.0.0.1:6379> BLPOP emptyqueue 5
(nil)
(5.01s)
# 可以同时监听多个列表
127.0.0.1:6379> BLPOP queue1 queue2 queue3 10
# 哪个列表先有元素就从哪个弹出
# 生产者:向队列推送任务
127.0.0.1:6379> RPUSH task:queue "send_email:user123"
(integer) 1
127.0.0.1:6379> RPUSH task:queue "process_order:order456"
(integer) 2
# 消费者:从队列获取任务
127.0.0.1:6379> BLPOP task:queue 0
1) "task:queue"
2) "send_email:user123"
# Python实现
import redis
r = redis.Redis()
# 生产者
def produce_task(task):
r.rpush("task:queue", task)
# 消费者
def consume_task():
while True:
task = r.blpop("task:queue", timeout=0)
if task:
queue_name, task_data = task
print(f"Processing: {task_data}")
# 处理任务...
# 发布动态(最新的在前面)
127.0.0.1:6379> LPUSH timeline:user:1001 "发布了新文章"
(integer) 1
127.0.0.1:6379> LPUSH timeline:user:1001 "点赞了一条微博"
(integer) 2
127.0.0.1:6379> LPUSH timeline:user:1001 "评论了一张照片"
(integer) 3
# 获取最新10条动态
127.0.0.1:6379> LRANGE timeline:user:1001 0 9
1) "评论了一张照片"
2) "点赞了一条微博"
3) "发布了新文章"
# 限制动态数量(只保留最新100条)
127.0.0.1:6379> LTRIM timeline:user:1001 0 99
OK
# 添加文章ID到列表
127.0.0.1:6379> RPUSH articles:latest 1001 1002 1003 1004 1005
(integer) 5
# 分页查询(每页2条)
# 第1页(索引0-1)
127.0.0.1:6379> LRANGE articles:latest 0 1
1) "1001"
2) "1002"
# 第2页(索引2-3)
127.0.0.1:6379> LRANGE articles:latest 2 3
1) "1003"
2) "1004"
# 第3页(索引4-5)
127.0.0.1:6379> LRANGE articles:latest 4 5
1) "1005"
# 使用LPUSH和LPOP实现栈(后进先出)
127.0.0.1:6379> LPUSH stack "A"
(integer) 1
127.0.0.1:6379> LPUSH stack "B"
(integer) 2
127.0.0.1:6379> LPUSH stack "C"
(integer) 3
# 弹出元素(后进先出)
127.0.0.1:6379> LPOP stack
"C"
127.0.0.1:6379> LPOP stack
"B"
127.0.0.1:6379> LPOP stack
"A"
# 使用RPUSH和LPOP实现队列(先进先出)
127.0.0.1:6379> RPUSH queue "task1"
(integer) 1
127.0.0.1:6379> RPUSH queue "task2"
(integer) 2
127.0.0.1:6379> RPUSH queue "task3"
(integer) 3
# 弹出元素(先进先出)
127.0.0.1:6379> LPOP queue
"task1"
127.0.0.1:6379> LPOP queue
"task2"
127.0.0.1:6379> LPOP queue
"task3"
| 命令 | 功能 | 时间复杂度 | 应用场景 |
|---|---|---|---|
| LPUSH/RPUSH | 头部/尾部插入 | O(1) | 消息队列、栈 |
| LPOP/RPOP | 头部/尾部弹出 | O(1) | 消息队列、栈 |
| LRANGE | 范围查询 | O(N) | 分页、时间线 |
| LINDEX | 索引查询 | O(N) | 随机访问 |
| LLEN | 获取长度 | O(1) | 统计 |
| LREM | 删除元素 | O(N) | 清理数据 |
| LTRIM | 保留范围 | O(N) | 限制列表大小 |
| BLPOP/BRPOP | 阻塞弹出 | O(1) | 消息队列 |
本课程深入讲解了Redis List类型的各种操作命令:
List是Redis中非常实用的数据类型,特别适合需要保持顺序的场景。掌握List的各种操作命令和应用场景,能够帮助我们更好地设计和实现各种功能。