JSON字段操作报错主因有三:字段非原生JSON类型、内容非法、路径语法错误;须用SHOW COLUMNS确认类型、JSON_VALID校验合法性、路径键名强制双引号包裹。

查字段类型是否真为 JSON
报错常源于“以为是JSON,其实只是VARCHAR”——MySQL 8.0 的 ->>、JSON_EXTRACT 等语法只对原生 json 类型生效。若字段实际是 text 或 varchar,执行 WHERE info->>'$.email' 会触发 FUNCTION database.JSON_UNQUOTE does not exist 错误。
必须用这条语句确认:
SHOW COLUMNS FROM users LIKE 'info';
看 Type 列是否严格显示 json。不是就别硬上 ->>,改用 whereRaw('JSON_EXTRACT(info, "$.email") = ?', [$val]),但注意 $val 必须是合法 JSON 字符串(如 "\"test@example.com\"")。
查 JSON 内容是否合法
MySQL 8.0 对 JSON 校验更严:老数据存的是带多余逗号、单引号、尾部逗号的“伪 JSON”,升级后 JSON_VALID(info) 直接返回 0,后续所有 JSON_* 函数都返回 NULL 或报错。
快速验证方式:
- 运行
SELECT id, info, JSON_VALID(info) AS valid FROM users WHERE JSON_VALID(info) = 0 LIMIT 5;找出非法记录 - 用
JSON_ERROR_MESSAGE(JSON_VALID(info))(需 MySQL 8.0.29+)或客户端json_last_error_msg()定位具体语法错误点 - 修复建议:用
UPDATE users SET info = TRIM(BOTH '"' FROM REPLACE(REPLACE(info, "'", '"'), '""', '"')) WHERE ...清洗后再JSON_VALID校验
查路径表达式是否含非法字符
MySQL 8.0 要求 JSON 路径中的键名必须用双引号包裹,尤其当键含数字、短横线、空格或保留字时。写成 '$.user.id-1' 或 '$.order 2' 会直接报 Invalid path expression。
正确写法必须是:
'$.user."id-1"''$.order."2"''$."user name"'
如果路径来自变量拼接,务必先用 json_encode($key, JSON_UNESCAPED_UNICODE) 包一层再注入路径字符串,避免手动拼引号出错。
查隐式转换是否破坏索引或比较逻辑
两个看似等价的写法,行为可能完全不同:
-
WHERE info->'$.status'返回带双引号的 JSON 字符串"active",和 PHP 中的'active'比较永远不等 -
WHERE info->>'$.status'返回无引号纯值active,可直接用于=、LIKE、IN - 更隐蔽的是排序规则冲突:虚拟列用
utf8mb4_0900_ai_ci,而JSON_EXTRACT返回值默认是utf8mb4_bin,导致索引失效(EXPLAIN显示Using where但没走索引)
解决方法:显式指定排序规则,例如建虚拟列时加 COLLATE utf8mb4_0900_ai_ci,或查询时用 WHERE info->>'$.status' COLLATE utf8mb4_0900_ai_ci = 'active'。
最易被忽略的是:JSON 字段在 GROUP BY 或 ORDER BY 中不能直接使用路径表达式,必须先提取到生成列,否则触发 Invalid use of NULL value 或静默跳过排序。这和普通字段的行为差异极大,得提前绕开。


















