“WRONGTYPE Operation against a key holding the wrong kind of value” 的意思很直白:命令的类型和 key 的实际类型不符。但真正麻烦的是怎么知道谁把别的类型写进了这个 key、事务和脚本里它会造成什么后果。这篇在本机把矩阵、覆盖、事务和排查都跑了一遍。
报错原文: LPUSH str x -> (error) WRONGTYPE Operation against a key holding the wrong kind of value 命令 string list hash set zset stream GET ok WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE STRLEN ok WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE APPEND ok WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE LLEN WRONGTYPE ok WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE LPUSH WRONGTYPE ok WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE HGET WRONGTYPE WRONGTYPE ok WRONGTYPE WRONGTYPE WRONGTYPE HSET WRONGTYPE WRONGTYPE ok WRONGTYPE WRONGTYPE WRONGTYPE SMEMBERS WRONGTYPE WRONGTYPE WRONGTYPE ok WRONGTYPE WRONGTYPE SADD WRONGTYPE WRONGTYPE WRONGTYPE ok WRONGTYPE WRONGTYPE ZRANGE WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE ok WRONGTYPE ZADD WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE ok WRONGTYPE XLEN WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE ok XADD WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE WRONGTYPE ok 对照:INCR 用在字符串但内容不是整数 -> (error) ERR value is not an integer or out of range(不是 WRONGTYPE)
每种类型有自己的一组命令,用错了就是 WRONGTYPE。INCR 对非整数字符串是另一个报错 ERR。
命令 string list hash set zset stream
TYPE ok ok ok ok ok ok
EXISTS ok ok ok ok ok ok
TTL ok ok ok ok ok ok
EXPIRE ok ok ok ok ok ok
OBJECT ENCODING ok ok ok ok ok ok
DUMP ok ok ok ok ok ok
COPY ok ok ok ok ok ok
RENAME ok ok ok ok ok ok
DEL ok ok ok ok ok ok
TYPE 的返回: [('str', 'string'), ('lst', 'list'), ('hsh', 'hash'), ('st', 'set'), ('zs', 'zset'), ('stm', 'stream')]TYPE、EXISTS、DEL、RENAME、COPY 等对所有类型都能用,遇到 WRONGTYPE 先 TYPE 一下。
覆盖前: TYPE lst = list,LLEN lst = 3 SET lst oops NX -> (nil)(key 已存在,没有写入);TYPE lst = list SET lst oops -> "OK" 覆盖后: TYPE lst = string,LLEN lst -> (error) WRONGTYPE Operation against a key holding the wrong kind of value 对照:RENAME 也会悄悄覆盖目标 key: RENAME str lst -> "OK",TYPE lst = string COPY 默认不覆盖: COPY str lst -> (integer) 0;加 REPLACE -> (integer) 1
SET 和 RENAME 不看原来的类型直接覆盖,数据悄悄丢失;SET NX 和 COPY(不带 REPLACE)不会覆盖。
MULTI 之后 SET a 1 -> "QUEUED" LPUSH str x(str 是字符串)-> "QUEUED"(入队时没有报错) SET b 2 -> "QUEUED" EXEC -> ['"OK"', 'WRONGTYPE…', '"OK"'] 之后 GET a = 1,GET b = 2(第 1、3 条已经生效) EVAL(SET w1;对字符串 LPUSH;SET w2)-> (error) WRONGTYPE Operation against a key holding the wrong kind of value script: ab9c978fb905e5925b4ea7ced1db6aa06edbe387, on @user_script:1. 之后 GET w1 = x,GET w2 = None(出错之前的 w1 留下了,出错之后的 w2 没有执行) 用 redis.pcall 捕获 -> "caught: WRONGTYPE Operation against a key holding the wrong kind of value"
EXEC 中某条命令 WRONGTYPE 时其它命令照常执行;Lua 里 redis.call 抛错会中止脚本,但此前的写入不回滚,redis.pcall 可以捕获。
user:* 共 50 个 key(50 个本来该是 hash):SCAN TYPE string 找到 3 个,hash 找到 47 个 混进来的字符串 key: ['user:7', 'user:23', 'user:41']
SCAN 的 TYPE 选项可以按类型分批找出命名空间里类型不一致的 key。