mysql 5.7+ json类型需规范使用:json_contains要求参数均为json类型且路径精确;取值用->>避免隐式转换;建索引须通过stored生成列实现;路径严格区分大小写且不可含空格。

MySQL 5.7+ 的 JSON 类型不是“能存 JSON 就完事了”,查不准、改不掉、索引失效是常态,核心问题在函数用错、路径写崩、类型隐式转换。
JSON_CONTAINS 为什么总返回 FALSE?
常见错误是把字符串当 JSON 值传进去,或者路径没写对。这个函数只认真正的 JSON 值,'{"id": 1}' 是字符串,JSON_OBJECT('id', 1) 或 CAST('{"id": 1}' AS JSON) 才是合法 JSON。
- 必须确保左右操作数都是
JSON类型,否则自动转成字符串后比对失败 - 第二个参数是「要查找的 JSON 值」,不是路径——比如查
{"tags": ["a", "b"]}是否含"a",得写JSON_CONTAINS(json_col, '"a"', '$.tags'),注意"a"要加双引号变成 JSON 字符串 - 路径表达式不支持通配符(如
$..name),只支持$开头的确定路径
怎么安全地从 JSON 字段取整数或布尔值?
直接用 json_col->'$.age' 拿到的是带引号的字符串(比如 "25"),参与数学运算会触发隐式转换,但一旦字段是 null 或格式不对就变 0,很隐蔽。
- 用
json_col->>'$.age'(注意>>)强制转成 MySQL 原生类型,->>等价于JSON_UNQUOTE(JSON_EXTRACT(...)) - 取布尔值时,
TRUE/FALSE在 JSON 里是小写,但 MySQL 解析后是 1/0,所以json_col->>'$.active'返回的是1或0,可直接用于WHERE - 如果不确定字段是否存在,
JSON_EXTRACT返回NULL,而->和->>在路径不存在时也返回NULL,这点一致
给 JSON 字段建索引为什么没生效?
MySQL 不支持直接对整个 JSON 列建索引,必须用生成列(generated column)+ 普通索引组合。漏掉任一环节,EXPLAIN 里都看不到 key。
- 先加生成列:
ALTER TABLE t ADD COLUMN status INT AS (json_col->>'$.status') STORED; - 再建索引:
CREATE INDEX idx_status ON t(status); - 查询时必须用生成列名,不能还写
json_col->>'$.status' = 1,否则索引不走——得写status = 1 - 生成列必须是
STORED(不能是VIRTUAL),因为只有STORED才能建索引
最常被忽略的是路径大小写和空格:JSON 路径严格区分大小写,$.Name 和 $.name 是两个东西;另外 -> 后面的路径字符串里不能有多余空格,json_col->' $.id ' 会解析失败,报 Invalid JSON path expression 错误。









