插入json数组必须用json_array()而非json_object();更新数组字段需用正确路径如$[0].field;json_set可新增路径,json_replace仅修改存在路径;批量更新需应用层处理或存储过程。

插入包含JSON数组的数据时,JSON_OBJECT 和 JSON_ARRAY 别混用
MySQL 5.7+ 支持原生 JSON 类型,但插入数组必须用 JSON_ARRAY(),不是 JSON_OBJECT()。后者生成的是键值对对象,强行塞进去会报错 Invalid JSON text 或静默转成字符串。
常见错误是把数组写成 JSON_OBJECT('items', '[{"id":1}]') —— 这只是字符串,不是合法 JSON 数组;正确写法是:
INSERT INTO users (name, preferences)
VALUES ('Alice', JSON_ARRAY(JSON_OBJECT('id', 1), JSON_OBJECT('id', 2)));
注意:JSON_ARRAY() 的每个参数都是独立的 JSON 值,不能传字符串拼接结果;如果数据来自变量,优先用 CAST(@str AS JSON) 转换,避免类型隐式转换失败。
用 JSON_SET 更新数组里某个对象的字段,得先定位路径
JSON 数组索引从 0 开始,路径写法是 $[0].field,不是 $[0]['field'](后者在 MySQL 里无效)。想更新第一个元素的 status 字段,直接写:
UPDATE users SET preferences = JSON_SET(preferences, '$[0].status', 'active') WHERE id = 123;
容易踩的坑:
- 路径不存在时,
JSON_SET会自动创建路径,但若数组越界(比如$[5]而实际只有 3 个元素),操作静默失败,不报错也不生效 - 如果不确定索引是否存在,先用
JSON_CONTAINS_PATH(preferences, 'one', '$[0].status')检查,再更新 -
JSON_SET只能设值,不能删字段;删字段要用JSON_REMOVE(preferences, '$[0].status')
JSON_REPLACE 和 JSON_SET 的行为差异直接影响更新逻辑
JSON_REPLACE 只更新已存在的路径,路径不存在就忽略;JSON_SET 会新增路径。这对部分字段更新很关键。
比如想“只改已有 status 字段,没有就不加”:
UPDATE users SET preferences = JSON_REPLACE(preferences, '$[0].status', 'pending');
而如果想“确保 status 字段存在,不管原来有没有”,就得用 JSON_SET。
性能上没明显差别,但语义不同:多数业务场景更适合 JSON_REPLACE,避免意外补全结构导致后续解析出错。
批量更新 JSON 数组中多个对象的同一字段,靠 JSON_OVERLAYS 不行,得用循环或应用层处理
MySQL 目前(8.0.29 之前)没有内置函数能遍历 JSON 数组并批量修改每个元素的字段。JSON_OVERLAYS 是误传,根本不存在;JSON_MERGE_PATCH 也不能按索引批量操作。
可行方案只有两个:
- 应用层取出来、用语言(如 Python/PHP)遍历修改、再整条写回 —— 简单可靠,适合中小数据量
- 用存储过程 +
WHILE循环 +JSON_EXTRACT逐个取、改、拼,但代码冗长且性能差,仅限无法改应用逻辑的遗留系统
别试图用 REPLACE() 字符串替换,JSON 结构稍复杂(比如字段名重复、嵌套引号)就会破坏合法性。











