MySQL中修改和删除JSON类型数据的实战教学
作者:detayun
MySQL 5.7开始原生支持JSON字段,提供了一套专门的JSON函数用来局部更新JSON,不推荐直接把整个JSON字符串覆盖写入,尤其是JSON对象比较大的时候,局部修改性能更好。本文演示常用更新语法、数组操作、生成列注意事项以及踩坑点。
MySQL中修改JSON类型
准备测试表
CREATE TABLE user_info (
id INT PRIMARY KEY AUTO_INCREMENT,
ext JSON COMMENT '扩展信息'
);
-- 插入测试数据
INSERT INTO user_info(ext) VALUES ('{"name":"张三","age":20,"tags":["开发","后端"]}');
JSON_SET:最常用,新增/更新字段
JSON_SET(json_doc, path, val, ...)
规则:路径存在就更新,不存在就新增,适合日常修改JSON对象。
-- 修改name,新增phone字段 UPDATE user_info SET ext = JSON_SET(ext, '$.name', '张三三', '$.phone', '13800138000') WHERE id = 1;
查询验证:
SELECT ext FROM user_info WHERE id = 1;
JSON_REPLACE:只更新已有字段,不会新增
JSON_REPLACE(json_doc, path, val,...)
路径存在才修改;路径不存在,不做任何操作。
-- 只修改age,尝试修改不存在的email不会生效 UPDATE user_info SET ext = JSON_REPLACE(ext, '$.age', 22, '$.email', 'test@demo.com') WHERE id = 1;
JSON_INSERT:只新增字段,不会覆盖已有值
JSON_INSERT(json_doc, path, val,...)
路径不存在才插入;已经存在则跳过,不会覆盖原有数据。
-- 新增email,name已存在不会被修改 UPDATE user_info SET ext = JSON_INSERT(ext, '$.email', 'test@demo.com', '$.name', '李四') WHERE id = 1;
三者简单区分
- JSON_SET:有则改,无则加(日常首选)
- JSON_REPLACE:只改已有,不加新key
- JSON_INSERT:只加新key,不改旧值
删除JSON内key:JSON_REMOVE
删除JSON对象中的某个key,或者数组指定下标元素
-- 删除phone字段 UPDATE user_info SET ext = JSON_REMOVE(ext, '$.phone') WHERE id = 1;
JSON数组修改操作
测试数据:"tags":["开发","后端"]
追加元素 JSON_ARRAY_APPEND
UPDATE user_info SET ext = JSON_ARRAY_APPEND(ext, '$.tags', 'MySQL') WHERE id = 1;
在数组开头插入 JSON_ARRAY_INSERT
-- 在数组下标0位置插入元素 UPDATE user_info SET ext = JSON_ARRAY_INSERT(ext, '$.tags[0]', '全栈') WHERE id = 1;
注意:数组下标从0开始;数组元素删除同样用 JSON_REMOVE $.tags[0]
批量多路径更新
一条语句同时修改多个key,减少update次数
UPDATE user_info
SET ext = JSON_SET(ext,
'$.name', '王五',
'$.age', 25,
'$.address.city', '重庆'
) WHERE id = 1;
JSON字段更新 + 索引相关重点
如果基于JSON字段创建生成列索引,更新JSON会同步更新生成列,和普通字段更新一样,需要维护索引成本。
示例:
-- 创建生成列并加索引 ALTER TABLE user_info ADD COLUMN user_name VARCHAR(50) GENERATED ALWAYS AS (ext->>'$.name') STORED; CREATE INDEX idx_username ON user_info(user_name);
更新ext里的name时,生成列自动同步,索引自动维护,不需要手动操作生成列。
常见坑点
路径语法错误:路径 $ 代表根节点,$.key 对象属性;数组 $.arr[0],写错路径不会报错,但不会生效。->> 是取出不带引号的字符串,-> 取出带双引号JSON字符串,写update path不要混用。
不要直接字符串覆盖
-- ❌ 不推荐,整个JSON重写,大JSON性能差
UPDATE user_info SET ext='{"name":"xxx"}' WHERE id=1;
-- ✅ 推荐局部修改 JSON_SET
JSON函数返回新JSON,必须赋值回ext:SET ext = JSON_SET(ext, ...) 不能省略 ext=,很多新手踩坑。
NULL的处理:如果ext字段本身是NULL,JSON_SET会返回NULL,不会自动创建JSON对象。
解决方案:使用 JSON_OBJECT() 兜底
UPDATE user_info SET ext = JSON_SET(IFNULL(ext, JSON_OBJECT()), '$.name', '测试') WHERE id = 1;
事务与锁:JSON字段更新属于行更新,InnoDB会加行锁,高并发场景下频繁更新JSON大字段容易产生锁等待。
什么时候不建议使用JSON字段更新
- 需要频繁检索JSON内部key,大量查询:优先拆成独立字段
- 超大JSON文档(几KB以上),频繁局部更新:MySQL JSON存储会产生碎片,建议应用层处理
MySQL 删除 JSON 类型的数据实战
MySQL JSON 的删除分两个层面:① 删除 JSON 文档内部的 key / 数组元素(JSON_REMOVE);② 删除整条包含 JSON 字段的数据行。很多人容易混淆,本文把两种场景的用法、示例、坑点一次性讲清楚。
准备测试表
CREATE TABLE user_info (
id INT PRIMARY KEY AUTO_INCREMENT,
ext JSON COMMENT '用户扩展信息'
);
INSERT INTO user_info(ext)
VALUES ('{"name":"张三","age":22,"phone":"13800138000","tags":["后端","MySQL","开发"],"address":{"city":"重庆","area":"渝北"}}');
删除JSON内部的key:JSON_REMOVE
语法:JSON_REMOVE(json_doc, path[, path] ...)
作用:移除 JSON 文档指定路径的数据,返回新的 JSON 文档。支持一次性删除多个key。
1. 删除一级key
删除 phone 字段:
UPDATE user_info SET ext = JSON_REMOVE(ext, '$.phone') WHERE id = 1;
2. 删除嵌套对象内的key
删除 address 里面的 area:
UPDATE user_info SET ext = JSON_REMOVE(ext, '$.address.area') WHERE id = 1;
3. 一次性删除多个key
同时删除 age 和 address:
UPDATE user_info SET ext = JSON_REMOVE(ext, '$.age', '$.address') WHERE id = 1;
删除JSON数组中的元素
数组下标从 0 开始,同样使用 JSON_REMOVE。
原始数据:"tags":["后端","MySQL","开发"]
删除下标1的元素(MySQL):
UPDATE user_info SET ext = JSON_REMOVE(ext, '$.tags[1]') WHERE id = 1;
重要特性:删除数组元素后,数组下标会自动前移。
例如:[A,B,C] 删除下标1(B),数组变成 [A,C],C 的下标从2变成1。
如果循环删除数组元素,必须从后往前删,否则下标错乱。
示例:从后往前删除数组多个元素,避免下标偏移问题
UPDATE user_info SET ext = JSON_REMOVE(ext, '$.tags[2]','$.tags[1]') WHERE id = 1;
清空JSON字段(置为空对象/空数组)
将JSON字段设置为空对象 {}
UPDATE user_info SET ext = JSON_OBJECT() WHERE id = 1;
将JSON字段设置为空数组 []
UPDATE user_info SET ext = JSON_ARRAY() WHERE id = 1;
直接置为NULL
UPDATE user_info SET ext = NULL WHERE id = 1;
删除整行数据(整条记录)
如果不需要这条记录,直接 DELETE,JSON字段会跟着一起删除:
-- 删除id=1的整行 DELETE FROM user_info WHERE id = 1;
根据JSON内部条件删除行
根据JSON内部key的值,筛选并删除整条记录:
-- 删除 ext->name = '张三' 的行 DELETE FROM user_info WHERE ext->>'$.name' = '张三';
高频踩坑点
JSON_REMOVE 不会修改原数据,必须赋值回字段
-- ❌ 错误写法,不会生效 UPDATE user_info SET JSON_REMOVE(ext, '$.phone') WHERE id=1; -- ✅ 正确写法,函数返回新json,要赋值给ext UPDATE user_info SET ext = JSON_REMOVE(ext, '$.phone') WHERE id=1;
路径不存在不会报错,直接原样返回:写了错误的path,SQL执行成功,但是数据没有任何变化,不会抛出异常。调试时先用SELECT验证路径:
SELECT JSON_REMOVE(ext, '$.not_exist_key') FROM user_info WHERE id=1;
ext字段为NULL时,JSON_REMOVE返回NULL:如果ext本身是NULL,JSON_REMOVE无法操作,不会自动创建JSON对象。
生成列索引影响:如果JSON创建了生成列(STORED),删除JSON内对应的key,生成列会同步更新,索引会自动维护,会产生少量性能开销。
数组删除下标偏移大坑:数组顺序删除下标0、1、2会出错。因为删掉下标0之后,原来下标1的数据变成下标0。删除多个数组元素,永远从最大下标往最小下标删。
小结
- 删除JSON内部key/数组元素:
JSON_REMOVE+ UPDATE - 清空JSON字段:
JSON_OBJECT()/JSON_ARRAY()/ NULL - 删除整条记录:
DELETE,支持JSON内部条件过滤 - 数组批量删除:从后往前删除下标,防止下标错位
小提示:如果业务频繁对JSON数组做增删操作,且需要根据数组元素检索,MySQL原生JSON数组性能较差,建议拆成独立子表。
到此这篇关于MySQL中修改和删除JSON类型数据的实战教学的文章就介绍到这了,更多相关MySQL修改和删除JSON数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
