Redis命令:LPUSHX

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 系列命令都是"有则推无则弃"。

相关推荐
用户094248568038 小时前
第19章:库存扣减与秒杀系统:Redis 扛峰值流量
redis·架构·源码
爱写Bug的浮游8 小时前
RTA高频请求下的Redis短缓存工程闭环
redis
没有气的汽水8 小时前
redis加了个分片,把线上写挂了一个多小时
redis
lsc_blog8 小时前
年底还在招的岗位,先确认缺口和到岗要求
git·缓存·ci/cd·职场和发展·github
xixiaoyunya10 小时前
Redis缓存三大问题实战:穿透、击穿、雪崩,我用一个电商秒杀场景讲清楚
数据库·redis·缓存
鶴哥只手遮天11 小时前
《Redis 8.10.3 深度剖析》系列 · 第 1 章·全景与源码地图:版本谱系、构建体系、全局状态与启动链路
redis·后端·开源
70后写java的老码农11 小时前
docker-compose 部署 Redis Stack Server 6.2.6-v19
redis·docker
小南家的青蛙13 小时前
Redis监控与告警体系化实践
redis·监控方案·告警方案
我不会起名字32213 小时前
Redis 从 0 到 1(二十七):JSON 体积是 Protobuf 的 3.7 倍?3 种序列化的 Go 基准测试
redis·go·序列化·protobuf·messagepack