json_set是“有就改、无就加”,json_replace是“有才改、无则跳过”;json_insert仅当路径不存在时插入,三者适用场景不同。

JSON_SET 和 JSON_REPLACE 的行为差异很明确
两者都用于修改 JSON 字段,但对“路径已存在”和“路径不存在”两种情况的处理完全不同。别记混——JSON_SET 是“有就改、无就加”,JSON_REPLACE 是“有才改、无则跳过”。这是最核心的区分点,也是线上出错最常见的根源。
什么时候必须用 JSON_REPLACE 而不是 JSON_SET
当你只想更新已有字段、绝对不允许新增字段时,JSON_REPLACE 是唯一安全的选择。比如用户资料表里只允许修改 $.phone 或 $.email,但不能意外插入 $.admin_flag 这类敏感键。
- 如果目标路径不存在,
JSON_REPLACE完全不改动原 JSON,返回原值 - 只要任一
path参数为NULL,整个函数返回NULL(注意不是空字符串) - 多个 path/val 对中,只有存在的路径会被替换,其余被忽略
- 示例:
SELECT JSON_REPLACE('{"a": 1}', '$.b', 2, '$.a', 99);→{"a": 99}($.b不存在,被跳过)
JSON_SET 在 UPDATE 语句里最容易踩的坑
JSON_SET 看似灵活,但在线上 UPDATE 场景中容易因路径误写或 NULL 值导致静默失败或数据污染。
- 路径写错(比如写成
'$.user.name'但实际是'$.user[0].name'),它会直接创建新键,而不是报错 - 如果传入的
val是NULL,对应路径会被设为 JSONnull(不是 SQL NULL),例如JSON_SET('{"a":1}', '$.b', NULL)→{"a":1,"b":null} - 在
UPDATE中使用时,务必确认WHERE条件能精确命中目标行,否则可能批量写入错误结构 - 示例:
UPDATE users SET info = JSON_SET(info, '$.status', 'active') WHERE id = 123;—— 如果info为NULL,结果仍是NULL,不会自动初始化为空对象
JSON_INSERT 适合什么场景
JSON_INSERT 不是 JSON_SET 和 JSON_REPLACE 的中间态,而是独立用途:只做“首次注入”,类似配置项的“默认填充”。
- 典型用法:给老数据补默认字段,如
JSON_INSERT(info, '$.created_at', NOW()),仅当$.created_at不存在时才写入 - 对数组路径也有效,比如
JSON_INSERT('{"tags": []}', '$.tags[0]', "new")→{"tags": ["new"]} - 重复执行同一
JSON_INSERT不会覆盖,也不报错,适合幂等初始化逻辑 - 注意:它不支持嵌套路径自动创建,比如
'$.user.profile.avatar'中若user或profile不存在,整个插入失败(返回原 JSON)
真正麻烦的不是函数本身,而是路径表达式写错后 JSON 结构悄悄变形,又没日志可查。建议所有生产环境的 JSON 更新操作,先用 SELECT 预览结果,再执行 UPDATE。










