MySQL中修改JSON类型的数据实战

前言:MySQL 5.7开始原生支持JSON字段,提供了一套专门的JSON函数用来局部更新JSON,不推荐直接把整个JSON字符串覆盖写入,尤其是JSON对象比较大的时候,局部修改性能更好。本文演示常用更新语法、数组操作、生成列注意事项以及踩坑点。

一、准备测试表

sql 复制代码
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对象。

sql 复制代码
-- 修改name,新增phone字段
UPDATE user_info 
SET ext = JSON_SET(ext, '$.name', '张三三', '$.phone', '13800138000')
WHERE id = 1;

查询验证:

sql 复制代码
SELECT ext FROM user_info WHERE id = 1;

三、JSON_REPLACE:只更新已有字段,不会新增

JSON_REPLACE(json_doc, path, val,...)

路径存在才修改;路径不存在,不做任何操作。

sql 复制代码
-- 只修改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,...)

路径不存在才插入;已经存在则跳过,不会覆盖原有数据。

sql 复制代码
-- 新增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,或者数组指定下标元素

sql 复制代码
-- 删除phone字段
UPDATE user_info
SET ext = JSON_REMOVE(ext, '$.phone')
WHERE id = 1;

六、JSON数组修改操作

测试数据:"tags":["开发","后端"]

  1. 追加元素 JSON_ARRAY_APPEND
sql 复制代码
UPDATE user_info
SET ext = JSON_ARRAY_APPEND(ext, '$.tags', 'MySQL')
WHERE id = 1;
  1. 在数组开头插入 JSON_ARRAY_INSERT
sql 复制代码
-- 在数组下标0位置插入元素
UPDATE user_info
SET ext = JSON_ARRAY_INSERT(ext, '$.tags[0]', '全栈')
WHERE id = 1;

⚠️ 注意:数组下标从0开始;数组元素删除同样用 JSON_REMOVE $.tags[0]

七、批量多路径更新

一条语句同时修改多个key,减少update次数

sql 复制代码
UPDATE user_info
SET ext = JSON_SET(ext,
    '$.name', '王五',
    '$.age', 25,
    '$.address.city', '重庆'
) WHERE id = 1;

八、JSON字段更新 + 索引相关重点

如果基于JSON字段创建生成列索引 ,更新JSON会同步更新生成列,和普通字段更新一样,需要维护索引成本。

示例:

sql 复制代码
-- 创建生成列并加索引
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时,生成列自动同步,索引自动维护,不需要手动操作生成列。

九、常见坑点

  1. 路径语法错误

    路径 $ 代表根节点,$.key 对象属性;数组 $.arr[0],写错路径不会报错,但不会生效。

    ->> 是取出不带引号的字符串,-> 取出带双引号JSON字符串,写update path不要混用。

  2. 不要直接字符串覆盖

sql 复制代码
-- ❌ 不推荐,整个JSON重写,大JSON性能差
UPDATE user_info SET ext='{"name":"xxx"}' WHERE id=1;
-- ✅ 推荐局部修改 JSON_SET
  1. JSON函数返回新JSON,必须赋值回ext

    SET ext = JSON_SET(ext, ...) 不能省略 ext=,很多新手踩坑。

  2. NULL的处理

    如果ext字段本身是NULL,JSON_SET会返回NULL,不会自动创建JSON对象。

    解决方案:使用 JSON_OBJECT() 兜底

sql 复制代码
UPDATE user_info 
SET ext = JSON_SET(IFNULL(ext, JSON_OBJECT()), '$.name', '测试')
WHERE id = 1;
  1. 事务与锁
    JSON字段更新属于行更新,InnoDB会加行锁,高并发场景下频繁更新JSON大字段容易产生锁等待。

十、什么时候不建议使用JSON字段更新

  • 需要频繁检索JSON内部key,大量查询:优先拆成独立字段
  • 超大JSON文档(几KB以上),频繁局部更新:MySQL JSON存储会产生碎片,建议应用层处理

相关推荐
承渊政道1 小时前
【Python编程—从入门到实践】(让程序记得、恢复并解释失败:Python 文件、异常与JSON系统教程)
开发语言·python·pycharm·json·异常处理
竣达技术1 小时前
就地显示 + 远程上传,铅酸蓄电池在线监测完整解决方案
运维·数据库
HUIBUR科技1 小时前
AI 中枢,面向企业场景构建的 AI 智能体
前端·数据库·人工智能
for_ever_love__1 小时前
MySQL 优化器与 OPTIMIZER_TRACE:把‘为什么选这条计划‘问到水落石出
数据库·mysql·优化器·trace·optimizer·执行计划分析·cic
j7~2 小时前
【仿 RabbitMQ 项目】发布订阅消息队列 (篇九):队列数据管理,内存镜像 + SQLite 持久化实现
数据库·c++·分布式·sqlite·rabbitmq·队列数据管理
l1t2 小时前
DeepSeek总结的PostgreSQL中TABLESAMPLE 如何挑选行
数据库·sql
qyyyyy5702 小时前
WhatsApp 联系人表格怎么清洗?Excel 文本类型、重复号码与姓名冲突处理
数据库·自然语言处理·excel·hash
云贝贝贝2 小时前
Oracle 认证实战指南
数据库·oracle
靠沿2 小时前
MySQL数据库基础——事务
java·数据库·mysql