Redis LPUSHX 命令详细教程
LPUSHX 将一个或多个元素插入到列表的表头(左侧),与 LPUSH 的唯一区别是:只有当 Key 已存在且持有列表时才执行推入 ,Key 不存在时不创建、不报错,静默返回 0。它从 Redis 2.2.0 起提供,4.0.0 起支持一次推入多个元素,适合"只更新、不新建"的保护性写入场景。
资料合集:https://pan.quark.cn/s/10e98d308913、https://pan.quark.cn/s/f56bc69c5338
一、概览与语法
redis
LPUSHX key element [element ...]
| 项目 | 说明 |
|---|---|
| 数据类型 | List |
| 支持版本 | Redis 2.2.0 起;4.0.0 起接受多个 element |
| key | 目标列表 Key,必须已存在 |
| element | 一个或多个要推入的元素,按书写顺序逐个推到表头 |
| 返回值 | 推入后的列表长度;Key 不存在时返回 0 |
| 时间复杂度 | 每个元素 O(1),一次推 N 个为 O(N) |
| ACL | @write、@list、@fast |
| 命令标记 | write、fast、denyoom |
官方说明:仅当 key 已存在且持有列表时,LPUSHX 才将所有指定值插入到列表表头;与 LPUSH 相反,key 尚不存在时不执行任何操作。$TRAE_REF
二、基础示例
以下命令在测试实例的 redis-cli 中执行。文中结果是预期说明,未实际连接 Redis 运行。示例沿用官方文档的数据与结果。
redis
DEL tutorial:{lpushx}:mylist tutorial:{lpushx}:other
RPUSH tutorial:{lpushx}:mylist "World"
LPUSHX tutorial:{lpushx}:mylist "Hello"
LPUSHX tutorial:{lpushx}:other "Hello"
LRANGE tutorial:{lpushx}:mylist 0 -1
预期结果:RPUSH 返回 1;对已存在的 mylist 推入返回 2;对不存在的 other 推入返回 0,且不会创建该 Key(可用 EXISTS 确认为 0);LRANGE 返回 "Hello"、"World"。
三、与 LPUSH 的核心差异
| 对比项 | LPUSH | LPUSHX |
|---|---|---|
| Key 存在且为列表 | 推入并返回新长度 | 推入并返回新长度 |
| Key 不存在 | 先创建空列表再推入 | 不创建,返回 0 |
| 副作用 | 可能凭空产生新 Key | 无,绝不新建 Key |
| 支持多元素 | 2.4.0 起 | 4.0.0 起 |
这个差异决定了两者的适用面:LPUSH 适合初始化与常规写入;LPUSHX 把"判断存在"和"推入"合并成一次原子操作,避免"先 EXISTS 检查再 LPUSH"这种两步流程在并发下产生的竞态。
四、多元素推入顺序
与 LPUSH 一致,多个元素按参数顺序逐个推到表头,最后一个参数最终位于表头:
redis
DEL tutorial:{lpushx}:order
RPUSH tutorial:{lpushx}:order seed
LPUSHX tutorial:{lpushx}:order a b c
LRANGE tutorial:{lpushx}:order 0 -1
预期结果:LPUSHX 返回 4;LRANGE 返回 "c"、"b"、"a"、"seed"。版本注意:Redis 4.0 之前的 LPUSHX 每次只接受一个元素。
五、Key 不存在与类型错误
LPUSHX 返回 0 只有一种正常情形:Key 当前不存在(含刚被弹出最后一个元素而删除的情况)。列表类型不会以"空列表"形式存在,元素弹完 Key 即被删除。
| 场景 | 行为 |
|---|---|
| Key 不存在 | 不创建,返回 0 |
| Key 是其他类型 | 报 WRONGTYPE |
| Key 已存在且为列表 | 推入,返回新长度 |
| Key 设置过 TTL | 推入不清除过期时间,到期仍会被删除 |
redis
SET tutorial:{lpushx}:str text
LPUSHX tutorial:{lpushx}:str x
预期结果:对 String 类型执行报 WRONGTYPE,类型检查先于任何写入。
六、与相近命令的区别
| 命令 | 推入位置 | Key 不存在时 | 支持多元素 |
|---|---|---|---|
| LPUSHX | 表头(左侧) | 不创建,返回 0 | 4.0.0 起 |
| LPUSH | 表头(左侧) | 创建列表后推入 | 2.4.0 起 |
| RPUSHX | 表尾(右侧) | 不创建,返回 0 | 4.0.0 起 |
| RPUSH | 表尾(右侧) | 创建列表后推入 | 2.4.0 起 |
| LINSERT | 指定 pivot 前后 | 不创建,返回 0 | 不支持 |
四个 X 后缀命令(LPUSHX、RPUSHX)与两个普通推入命令的分工很清晰:普通命令负责"有则推、无则建",X 命令负责"有则推、无则放弃"。
七、边界情况与错误处理
| 场景 | 行为 |
|---|---|
| 未提供任何 element | 参数数量不足,报语法错误 |
| element 为空字符串 | 允许,正常推入 |
| Key 不存在 | 返回 0,静默成功 |
| Key 类型不是 List | 报 WRONGTYPE |
| 返回值语义 | 0 表示未推入(Key 不存在),正数表示推入后的长度 |
redis
LPUSHX tutorial:{lpushx}:err
预期结果:缺少元素参数,报 ERR wrong number of arguments for 'lpushx' command。
业务代码需要注意:LPUSHX 返回 0 不是错误,但通常意味着"列表尚未初始化",调用方应据此决定是否先执行初始化,而不是把它当成失败重试。
八、客户端示例
前提为已安装 redis-py 并准备好本地测试实例。redis-py 的 lpushx(name, *values) 返回推入后的长度,Key 不存在时返回 0。
python
import redis
r = redis.Redis(host="localhost", port=6379, decode_responses=True)
key = "tutorial:{lpushx}:py"
try:
r.delete(key)
print(r.lpushx(key, "a", "b", "c")) # 0,Key 不存在不创建
r.rpush(key, "seed")
print(r.lpushx(key, "a", "b", "c")) # 4
print(r.lrange(key, 0, -1)) # ['c', 'b', 'a', 'seed']
finally:
r.delete(key)
r.close()
Java(Jedis)示例,lpushx 同样支持可变参数:
java
try (Jedis jedis = new Jedis("localhost", 6379)) {
String key = "tutorial:{lpushx}:java";
jedis.del(key);
System.out.println(jedis.lpushx(key, "a"));
// 0,Key 不存在不创建
jedis.rpush(key, "seed");
System.out.println(jedis.lpushx(key, "a", "b", "c"));
// 4
System.out.println(jedis.lrange(key, 0, -1));
// [c, b, a, seed]
jedis.del(key);
}
九、原子性与使用注意事项
检查与写入合一 :EXISTS key 加 LPUSH key x 是两步流程,中间可能被其他客户端删除 Key 或改变类型;LPUSHX 把"必须已存在"作为前置条件在服务端一次性校验,是天然原子的。
TTL 不受影响:对已设置过期时间的 Key 执行 LPUSHX 不会清除 TTL。若业务期望"写入后重新计时",需要显式重设 EXPIRE。
Pipeline 与事务:LPUSHX 可正常用于管道与 MULTI/EXEC,返回值语义不变;批量推入用管道减少网络往返。
性能:每个元素 O(1),只操作表头,与列表长度无关。
十、典型业务场景
保护性追加:队列、Feed、操作历史等 Key 由专门的初始化逻辑(写入元数据、设置 TTL)创建后,后续写入全部走 LPUSHX,防止下游异常调用凭空造出没有 TTL、没有元数据的孤儿 Key。
会话期列表:用户会话存在才记录操作轨迹,会话过期后自然停止追加,无需额外判断。
并发初始化保护:多个服务实例同时写同一个列表时,用 LPUSHX 保证"谁负责创建、谁才能写入"的语义清晰。
十一、练习、排错与总结
练习:新建 tutorial:{lpushx}:ex1 与 tutorial:{lpushx}:ex2;对不存在的 ex1 执行 LPUSHX ex1 a,确认返回 0 且 EXISTS 为 0;执行 RPUSH ex1 seed 后执行 LPUSHX ex1 b c,确认返回 3 且 LRANGE 得到 c,b,seed;用 SET 把 ex1 改成 String 后再 LPUSHX,确认报 WRONGTYPE;最后对 ex2 重复验证 Key 不存在时的静默行为。
排错要点:LPUSHX 返回 0 时先怀疑 Key 未初始化,用 EXISTS、TYPE 确认;本想初始化列表时不要误用 LPUSHX,改用 LPUSH;报 WRONGTYPE 时检查 Key 是否被 String 等类型占用;老版本(4.0 前)报语法错误时检查是否使用了多元素写法。清理使用 DEL tutorial:{lpushx}:mylist tutorial:{lpushx}:other tutorial:{lpushx}:order tutorial:{lpushx}:str tutorial:{lpushx}:py tutorial:{lpushx}:java tutorial:{lpushx}:ex1 tutorial:{lpushx}:ex2。速记:2.2 起支持、4.0 起可推多个、只在 Key 已存在时推入、Key 不存在返回 0 且不创建、返回值为推入后的长度、不清除已有 TTL、与 LPUSH 的区别就在"是否创建"、X 系列命令都是"有则推无则弃"。