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存储会产生碎片,建议应用层处理

相关推荐
Small-Young1 小时前
数据库乐观锁深度解析:MySQL、PostgreSQL 实战 + Spring Boot 集成指南
数据库·spring boot·mysql·postgresql·乐观锁·并发控制
浮生若城1 小时前
MySQL 数据库基础
数据库·mysql
香蕉大香蕉(06敬畏市场)1 小时前
MySQL 单点详解(09)
java·数据库·mysql·面试·八股·大厂实习
瀚高PG实验室2 小时前
瀚高数据库运行日志(错误日志)查看与分析方法
数据库·postgresql·瀚高数据库
snow@li2 小时前
PostgreSQL:PostgreSQL(PG)全景深度梳理
数据库·postgresql
January12072 小时前
【AI方法笔记】2026-11-02:模型流式吐 JSON 时,前端会遇到四种崩法
前端·人工智能·笔记·json
java_nnnn2 小时前
Spring IoC & DI 从入门到理解:控制反转、依赖注入与 Bean 管理详解
数据库·sql·spring
瀚高PG实验室3 小时前
HGHAC集群版本升级
数据库·postgresql·瀚高数据库
品牌常新3 小时前
室外巡检机器人推荐:园区与厂区怎么选
数据库·人工智能·机器人
snow@li3 小时前
redis:RedisDesktopManager(RDM/RESP.app)Redis 数据可视化全景深度梳理
数据库·redis·缓存