MySQL JSON类型是校验+二进制存储+路径查询的结构化字段;VARCHAR存JSON会丢失校验、索引和路径查询能力;必须用合法JSON格式插入,提取用->(返回JSON)和->>(返回原生类型),高频查询需建STORED虚拟列+索引,数组/存在性判断须用JSON_CONTAINS等专用函数。

MySQL原生JSON类型不是“存字符串”,而是带校验、二进制存储和路径查询能力的结构化字段;直接用VARCHAR存JSON会丢掉所有这些能力,查不了路径、建不了索引、也拦不住非法格式。
建表时声明JSON类型并确保插入合法格式
建表语句里写JSON就完事,但插入必须是标准JSON:键名双引号、字符串值双引号、无尾随逗号、不支持单引号或未转义字符。
-
INSERT INTO products (specs) VALUES ('{"cpu":"i7","cores":8}');✅ 合法 -
INSERT INTO products (specs) VALUES ("{'cpu':'i7'}");❌ 单引号 + 格式错误 → 报错Invalid JSON text - 想从字符串转JSON,得显式
CAST('{"a":1}' AS JSON),否则自动当VARCHAR处理 - 空对象/数组可用
'{}'或'[]',不能用NULL(除非字段允许NULL)
用->和->>提取值,别混淆返回类型
->返回JSON类型值(带双引号),->>返回去引号后的MySQL原生类型(字符串、数字等),WHERE里直接比较必须用->>。
-
specs -> '$.cpu'返回"\"i7\""(JSON字符串),WHERE specs -> '$.cpu' = '"i7"'写法脆弱且易错 -
specs ->> '$.cpu'返回i7(无引号),WHERE specs ->> '$.cpu' = 'i7'才安全可靠 - 取嵌套字段如
$.address.city,路径含空格用$.["screen size"] - 路径不存在时返回
NULL,可用COALESCE(specs ->> '$.ram', '8GB')设默认值
高频查询字段必须建虚拟列+索引,否则全表扫描
JSON字段本身不能直接加索引,但可以基于路径表达式创建STORED虚拟列,再对其建普通索引——这是性能关键。
ALTER TABLE products ADD cpu_brand VARCHAR(20) AS (specs ->> '$.cpu') STORED;ALTER TABLE products ADD INDEX idx_cpu (cpu_brand);- 虚拟列必须
STORED(不能VIRTUAL),否则无法索引 - MySQL 8.0 支持多列函数索引,但5.7只支持单列虚拟列索引
数组和存在性判断要用专用函数,别硬拼字符串
查数组是否含某值、对象是否存在某个键,必须用JSON_CONTAINS和JSON_CONTAINS_PATH,手动LIKE或INSTR会漏匹配、错匹配。
-
JSON_CONTAINS(specs, '"SSD"', '$.storage'):第三个参数是路径,第二个参数必须是JSON格式字符串(带引号) -
JSON_CONTAINS_PATH(specs, 'one', '$.gpu'):'one'表示至少一个匹配,'all'表示全部路径都存在 - 数组元素定位用
$[0](0-indexed),specs ->> '$[1]'取第二个元素并去引号
真正容易被忽略的是虚拟列索引的STORED关键字和JSON_CONTAINS第二个参数的JSON格式要求——写错一个引号或漏掉STORED,索引就失效,查询照旧慢。


















