前言:MySQL5.7 开始正式支持原生JSON字段,8.0进一步增强JSON函数能力。很多开发会直接把JSON存成VARCHAR,但原生JSON会校验格式,并且提供内置函数方便读取、修改、删除JSON内的key和数组。这篇博客包含建表、查询、新增、修改、删除JSON数据,附带常用函数和避坑点。
一、测试表准备
sql
CREATE TABLE product (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
attr JSON COMMENT '商品扩展JSON属性'
);
-- 插入测试数据
INSERT INTO product(name, attr) VALUES
('手机', '{"color":"黑色","price":3999,"tags":["旗舰","5G"],"detail":{"weight":"200g","screen":"6.7英寸"}}'),
('耳机', '{"color":"白色","price":299,"tags":["蓝牙","降噪"],"detail":{"weight":"8g","screen":null}}');
二、JSON查询操作
1. -> 和 ->> 提取JSON字段值(最常用)
->:返回带双引号的JSON原始值->>:返回去掉双引号的字符串,日常查询优先用 ->>
sql
-- 查询商品名称、颜色、价格
SELECT
name,
attr->>'$.color' AS color,
attr->>'$.price' AS price
FROM product;
读取嵌套对象:
sql
SELECT name, attr->>'$.detail.weight' AS weight FROM product;
读取数组指定下标元素:
sql
-- 获取tags数组第0个元素
SELECT name, attr->>'$.tags[0]' AS tag1 FROM product;
2. JSON_EXTRACT()
-> 本质就是 JSON_EXTRACT() 的简写形式
sql
-- 等价 attr->>'$.color'
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr, '$.color')) FROM product;
3. 根据JSON内的值作为WHERE条件过滤
sql
-- 查询颜色为黑色的商品
SELECT name FROM product WHERE attr->>'$.color' = '黑色';
-- 查询价格大于1000
SELECT name FROM product WHERE attr->>'$.price' > 1000;
4. JSON数组包含判断 JSON_SEARCH
查找数组中是否包含指定元素
sql
-- 查询tags数组里面包含"降噪"的商品
SELECT name FROM product
WHERE JSON_SEARCH(attr, 'one', '降噪', null, '$.tags') IS NOT NULL;
参数说明:
one找到第一个匹配;all查找全部匹配。
5. JSON_KEYS 获取JSON对象所有key
sql
SELECT JSON_KEYS(attr) FROM product;
三、JSON写入(插入)
直接传入标准JSON字符串,或者使用JSON_OBJECT、JSON_ARRAY构造JSON:
sql
-- 方式1:直接字符串
INSERT INTO product(name,attr) VALUES ('平板','{"color":"灰色","price":2499}');
-- 方式2:函数构造,不用手动写引号,不容易出错
INSERT INTO product(name,attr) VALUES (
'手表',
JSON_OBJECT("color","银色","price",1299,"tags",JSON_ARRAY("智能","防水"))
);
四、JSON更新操作
JSON_SET:有则更新,无则新增(开发首选)
sql
UPDATE product
SET attr = JSON_SET(attr, '$.color', '深空灰', '$.stock', 100)
WHERE id = 1;
JSON_REPLACE:只更新已存在key,不存在则不处理
sql
UPDATE product
SET attr = JSON_REPLACE(attr, '$.price', 3699)
WHERE id = 1;
JSON_INSERT:只新增key,已有key不会覆盖
sql
UPDATE product
SET attr = JSON_INSERT(attr, '$.stock', 200)
WHERE id = 1;
JSON数组追加:JSON_ARRAY_APPEND
sql
UPDATE product
SET attr = JSON_ARRAY_APPEND(attr, '$.tags', '快充')
WHERE id = 1;
JSON数组指定位置插入:JSON_ARRAY_INSERT
sql
UPDATE product
SET attr = JSON_ARRAY_INSERT(attr, '$.tags[0]', '新品')
WHERE id = 1;
五、JSON删除操作 JSON_REMOVE
删除JSON对象key、数组元素
sql
-- 删除stock字段
UPDATE product
SET attr = JSON_REMOVE(attr, '$.stock')
WHERE id = 1;
-- 删除数组下标1的元素
UPDATE product
SET attr = JSON_REMOVE(attr, '$.tags[1]')
WHERE id = 1;
⚠️ 删除数组多个元素:从大下标往小下标删,删除后数组下标自动前移,顺序正向删除会导致下标错乱。
六、JSON生成列 + 索引(性能优化重点)
原生JSON字段内部key查询不走索引,大数据量查询会全表扫描。可以创建生成列并建立索引:
sql
-- 创建生成列,提取color字段
ALTER TABLE product ADD COLUMN color VARCHAR(50) GENERATED ALWAYS AS (attr->>'$.color') STORED;
-- 建立索引
CREATE INDEX idx_product_color ON product(color);
STORED:实际存储数据;VIRTUAL(默认)不占用存储空间,查询时实时计算,不支持加索引。
七、常见踩坑汇总
- **路径语法 不能省略** ,`.key
,嵌套.obj.key`(.obj.key`;数组 `) `.arr[0]` ->带引号,->>不带引号,做等值判断WHERE条件必须用 ->>- JSON函数返回新JSON文档,UPDATE时必须赋值回字段
attr=JSON_SET(...),否则不生效 - JSON字段本身为NULL时,JSON_SET / JSON_REMOVE都会返回NULL,可用
IFNULL(attr, JSON_OBJECT())兜底 - JSON数组查找
JSON_SEARCH只能匹配字符串;数字类型无法直接搜索,需要转换 - 不要用
LIKE模糊匹配JSON字符串,JSON内部空格、顺序变化会导致匹配失效 - 频繁查询JSON内部字段,优先拆成独立字段;JSON适合存储不常检索的扩展属性
八、函数速查表
| 函数 | 作用 |
|---|---|
| JSON_EXTRACT | 提取JSON值 |
| JSON_SET | 更新/新增key |
| JSON_REPLACE | 仅更新已有key |
| JSON_INSERT | 仅新增key |
| JSON_REMOVE | 删除key/数组元素 |
| JSON_ARRAY_APPEND | 数组末尾追加 |
| JSON_ARRAY_INSERT | 数组指定位置插入 |
| JSON_SEARCH | 查找数组/对象内文本 |
| JSON_OBJECT | 构建JSON对象 |
| JSON_ARRAY | 构建JSON数组 |