Redis命令:LREM
Redis LREM 命令详细教程LREM移除列表中与指定元素相等的前 count 个元素是按值删除列表元素的基础命令。count 同时决定删除数量与扫描方向可以从表头向表尾删、从表尾向表头删也可以一次性删完全部匹配。它从 Redis 1.0.0 起提供常用于清理队列中的无效任务或按值维护列表内容。资料合集https://pan.quark.cn/s/10e98d308913、https://pan.quark.cn/s/f56bc69c5338一、概览与语法LREM key count element项目说明数据类型List支持版本Redis 1.0.0 起key目标列表 Keycount移除数量与方向大于 0 从表头向表尾移除 count 个小于 0 从表尾向表头移除 count 的绝对值个等于 0 移除全部匹配元素element要移除的目标值按字节精确匹配返回值整数本次被移除的元素个数时间复杂度O(NM)N 为列表长度M 为被移除的元素数ACLwrite、list、slow命令标记write官方说明从存储于 key 的列表中移除前 count 个与 element 相等的元素。count 大于 0 时从表头向表尾移除count 小于 0 时从表尾向表头移除count 等于 0 时移除所有匹配元素。$TRAE_REF二、基础示例以下命令在测试实例的 redis-cli 中执行。文中结果是预期说明未实际连接 Redis 运行。示例沿用官方文档的数据与结果。DEL tutorial:{lrem}:mylist RPUSH tutorial:{lrem}:mylist hello RPUSH tutorial:{lrem}:mylist hello RPUSH tutorial:{lrem}:mylist foo RPUSH tutorial:{lrem}:mylist hello LREM tutorial:{lrem}:mylist -2 hello LRANGE tutorial:{lrem}:mylist 0 -1预期结果列表初始为hello、hello、foo、hello共 4 个元素LREM的 count 为 -2表示从表尾向表头移除 2 个hello返回2最后LRANGE返回hello、foo被移除的是末尾两个 hello表头 hello 与中间的 foo 保留。三、count 参数的三种语义count 的正负与零决定删除方向和数量用同一个列表分别验证DEL tutorial:{lrem}:ex RPUSH tutorial:{lrem}:ex a b a a LREM tutorial:{lrem}:ex 2 a LRANGE tutorial:{lrem}:ex 0 -1 DEL tutorial:{lrem}:ex RPUSH tutorial:{lrem}:ex a b a a LREM tutorial:{lrem}:ex -2 a LRANGE tutorial:{lrem}:ex 0 -1 DEL tutorial:{lrem}:ex RPUSH tutorial:{lrem}:ex a b a a LREM tutorial:{lrem}:ex 0 a EXISTS tutorial:{lrem}:ex预期结果列表初始为a、b、a、a。count 为 2 时从表头扫描移除索引 0 和 2 的两个 a返回2剩余b、acount 为 -2 时从表尾扫描移除索引 3 和 2 的两个 a返回2剩余a、bcount 为 0 时移除全部 3 个 a返回3列表被清空且 Key 随之删除EXISTS返回0。四、返回值与空结果LREM返回整数被移除的元素个数。返回 0 有两种不可区分的情形——Key 不存在或元素在列表中没有出现两种情况都不报错。情形返回移除了 N 个匹配元素NKey 不存在0元素在列表中未出现0如果业务需要区分“列表不存在”与“没匹配到元素”应额外执行 EXISTS 或 TYPE 判断不能只看 LREM 的返回值。EXISTS tutorial:{lrem}:ex LREM tutorial:{lrem}:ex 1 a LREM tutorial:{lrem}:mylist 5 no-such预期结果上一节 count 为 0 的示例已把 ex 清空并删除 KeyEXISTS返回0对不存在的 Key 执行LREM返回0对存在的 mylist 移除未出现的元素同样返回0三种结果无法从返回值区分。五、精确匹配语义字节级比较LREM按字节内容逐一比较元素A与a是不同的值。不支持通配符element 是普通字符串a*只匹配字面的a*不会匹配abc。空字符串可匹配element 为空字符串是合法的可以移除值为空串的元素。RPUSH tutorial:{lrem}:ex a A a* LREM tutorial:{lrem}:ex 0 a LRANGE tutorial:{lrem}:ex 0 -1预期结果LREM返回1只移除了小写的aLRANGE返回A、a*大写 A 与带星号的 a* 均未被误删。六、边界情况与错误处理场景行为Key 不存在返回 0不报错元素在列表中不存在返回 0不报错Key 类型不是 List报 WRONGTYPEcount 缺失或不是整数报语法错误或参数类型错误element 为空字符串允许按空串匹配count 为 0移除全部匹配元素SET tutorial:{lrem}:str text LREM tutorial:{lrem}:str 0 a预期结果对 String 类型执行报 WRONGTYPE类型检查先于匹配扫描。七、与相近命令的区别命令定位方式是否修改列表说明LREM按值匹配删除是变短按值删除前 count 个匹配元素LPOS按值查找返回索引否只定位不删除常与 LREM/LSET 组合LTRIM按索引区间保留是变短区间语义同 LRANGE与值无关LPOP / RPOP按位置弹出是变短只删表头或表尾一个元素不看值DEL / UNLINK删除整个 Key是连 Key 带数据整体删除选择思路知道值用LREM知道位置用LPOP/RPOP或LTRIM只想查找用LPOS整键放弃用DEL/UNLINK。八、客户端示例前提为已安装 redis-py 并准备好本地测试实例。redis-py 4.0 及以上版本的签名为lrem(name, count, value)旧版为lrem(name, value, num)升级时注意参数顺序。返回值为 int表示移除个数。importredis rredis.Redis(hostlocalhost,port6379,decode_responsesTrue)keytutorial:{lrem}:pytry:r.delete(key)r.rpush(key,a,b,a,a)print(r.lrem(key,2,a))# 2从表头移除两个 aprint(r.lrange(key,0,-1))# [b, a]print(r.lrem(key,0,a))# 1移除剩余的全部 aKey 随之删除print(r.lrem(key,1,a))# 0Key 已不存在print(r.lrem(no-such,1,a))# 0Key 不存在也不报错finally:r.delete(key)r.close()JavaJedis示例lrem返回longtry(JedisjedisnewJedis(localhost,6379)){Stringkeytutorial:{lrem}:java;jedis.del(key);jedis.rpush(key,a,b,a,a);System.out.println(jedis.lrem(key,-2,a));// 2从表尾移除两个 aSystem.out.println(jedis.lrange(key,0,-1));// [a, b]System.out.println(jedis.lrem(key,0,a));// 1删除最后一个 ajedis.del(key);}九、原子性与性能复杂度O(NM)N 为列表长度M 为被移除的元素数。即使只删 1 个元素最坏也要扫过整个列表定位它因此LREM在大列表上属于潜在慢命令。慢命令风险对十万级以上元素的列表执行LREM key 0 x会完整扫描并可能大规模改写节点阻塞事件循环。高频按值删除的场景应考虑改用 Hash、Set 或有序集合。原子性单命令原子并发客户端无需加锁在 MULTI/EXEC 与 Lua 脚本中可将多次 LREM 与其他命令组合成整体事务。读改写组合非原子先 LPOS 定位再 LREM 的两步操作之间可能被其他客户端插入需要严格一致时用 WATCH 或 Lua 脚本包裹。十、典型业务场景队列清理延迟队列中任务已失败或被取消用LREM key 1 task-id按值移除该任务。按值去重列表被写入方重复投递后用LREM key 0 value清掉某值的全部副本。白名单维护以 List 存放 IP 或用户白名单退订时LREM key 1 user-id摘除。先定位再删除先用LPOS key element确认值的位置与份数再决定 count 用 1 还是 0避免误删。十一、练习、排错与总结练习新建tutorial:{lrem}:ex用 RPUSH 写入x y x z x执行LREM ex 1 x确认返回1且剩余y x z x只删表头的 x再执行LREM ex -2 x返回2且剩余y z重建列表后执行LREM ex 0 x返回3且EXISTS为0对不存在的 Key 执行LREM返回0不报错对 String Key 执行报 WRONGTYPE。排错要点返回 0 时先区分 Key 不存在与值未出现用 EXISTS/TYPE 进一步判断删多了通常是 count 误写成 0 或弄反了正负方向没删干净检查值是否大小写或前后空格不一致报 WRONGTYPE 时用 TYPE 检查类型慢日志出现 LREM 时评估列表长度并考虑换数据结构。清理使用DEL tutorial:{lrem}:mylist tutorial:{lrem}:ex tutorial:{lrem}:str tutorial:{lrem}:py tutorial:{lrem}:java。速记1.0 起支持、count 正头负尾零全部、返回被移除个数、返回 0 表示没删到Key 不存在或未匹配二者不可区分、按字节精确匹配区分大小写、O(NM) 大列表是慢命令、单命令原子、按值删除直接用 LREM 而不是先 LRANGE 再逐个删。