升级mysql 8.0后json函数报错主因是字段类型非json、路径未加引号、数据不合法或索引失效;须先确认type为json,路径用'$."key"'格式,校验json_valid(),并用虚拟列+索引优化性能。

升级到 MySQL 8.0 后 JSON 字段函数报错,**大概率不是语法写错了,而是字段类型、路径写法或数据合法性出了问题**。8.0 对 JSON 的校验更严、路径解析更死板、索引行为也变了,光靠“把旧 SQL 复制过来跑”基本会踩坑。
确认字段类型是不是真正的 JSON
这是所有问题的起点。很多升级后报错,是因为表结构里字段仍是 VARCHAR 或 TEXT,但代码里用了 ->> 或 JSON_EXTRACT —— MySQL 8.0 会直接报 FUNCTION database.JSON_UNQUOTE does not exist。
- 先执行
SHOW COLUMNS FROM table_name LIKE 'col_name';,检查Type列是否为json - 如果不是,别强行用 JSON 函数,要么
ALTER TABLE table_name MODIFY col_name JSON;(需确保现有数据全合法),要么改用whereRaw('JSON_EXTRACT(col_name, "$.key") = ?', [$val])配合手动json_encode处理参数 -
JSON_VALID(col_name)在VARCHAR字段上能用,但在JSON字段上才是强制校验入口;类型不对时,它可能返回NULL而不是0,逻辑判断要留心
Invalid JSON path expression 错误怎么修
典型现象:同一句 SELECT * FROM t WHERE JSON_EXTRACT(json_col, '$.user.info.id') > 1,5.7 跑得通,8.0 报错。这是因为 8.0 要求路径中含点号的 key 必须加双引号,否则视为非法标识符。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
- 错误写法:
'$.user.info.id'→ 8.0 认为info.id是一个未加引号的路径段 - 正确写法:
'$."user"."info"."id"'或更稳妥的'$.`user`.`info`.`id`'(反引号在部分客户端更兼容) - 嵌套数组路径同理:
'$[0]."items"[1]."price"',不能省略任何一层的引号 - 如果路径是动态拼的,PHP 侧要用
addcslashes($key, '"')包裹后再拼进字符串,避免引号冲突
查询结果为空但数据明明存在?检查 NULL 和空字符串
常见于 whereJsonContains、JSON_CONTAINS 或 ->> 查询返回空集,实际字段里有值。根本原因往往是字段值为 NULL、''(空字符串)或 'null'(字符串)——这些在 8.0 下全被 JSON_VALID() 判为非法,导致函数静默失败。
- 查非法数据:
SELECT id, json_col FROM table_name WHERE json_col IS NULL OR json_col = '' OR JSON_VALID(json_col) = 0; -
JSON_VALID('null')返回1(合法),但JSON_VALID("null")(单引号)返回0;注意引号类型 - 应用层写入前必须做兜底:
$data = $input ?: [];,再json_encode($data, JSON_UNESCAPED_UNICODE),绝不能让空值直通入库 - 建表时加约束最保险:
feature_data JSON CHECK (JSON_VALID(feature_data) AND feature_data != '')
性能突然暴跌?别急着优化 SQL,先看索引有没有生效
升级后响应从 200ms 涨到 3s,EXPLAIN 显示 type: ALL,说明 JSON 路径查询根本没走索引。8.0 的函数索引对写法极其敏感,差一个 CAST 就失效。
- 虚拟列 + 索引最稳:
ALTER TABLE t ADD COLUMN status ENUM('active','inactive') STORED AS (JSON_UNQUOTE(JSON_EXTRACT(json_col, '$."status"'))) NOT NULL, ADD INDEX idx_status(status); - 函数索引写法必须完全一致:建索引用
CAST(JSON_EXTRACT(json_col, '$."status"') AS CHAR(20)),查询也必须写成WHERE CAST(JSON_EXTRACT(json_col, '$."status"') AS CHAR(20)) = 'active' -
JSON_TABLE在百万级数据下性能衰减明显,同等场景用虚拟列快 5–8 倍,别被语法炫酷带偏 - 确认索引是否被选中:
SELECT * FROM information_schema.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME LIKE '%json%';
真正麻烦的从来不是“怎么写对”,而是“为什么看起来对却没效果”——MySQL 8.0 的 JSON 校验链太长:字段类型 → 数据合法性 → 路径语法 → 索引定义 → 查询写法,任一环松动,结果就不可控。上线前务必用生产数据抽样跑 JSON_VALID() + EXPLAIN 双验证。










