JSON_OBJECT在MySQL中遇NULL值默认跳过该键,全为NULL时返回NULL而非{};5.7要求键值成对且键为字面量,8.0支持表达式键名;安全做法需预处理键名并用JSON_SET避免注入。
JSON_OBJECT 生成空对象或 NULL 值时的行为
MySQL 的 JSON_OBJECT 在参数成对缺失(比如只传一个键不传值,或值为 NULL)时,**不会报错,但会静默跳过该键值对**。这容易导致构造结果比预期少字段,尤其在动态拼接场景下难排查。
- 如果
JSON_OBJECT('name', @name, 'age', @age)中@name为NULL,整个'name'键会被丢弃,最终对象里根本没有name字段 - 若所有值全为
NULL,JSON_OBJECT()返回NULL,而非空对象{} - 想强制保留键(哪怕值是
null),得显式用CAST(NULL AS JSON)或JSON_OBJECT('key', JSON_NULL())
MySQL 5.7 vs 8.0 的参数限制差异
MySQL 5.7 要求 JSON_OBJECT 参数必须成对出现(键、值各一个),且键名必须是字符串字面量或变量;而 MySQL 8.0 支持更灵活的用法,比如用表达式生成键名,或嵌套调用。
- 5.7 不支持:
JSON_OBJECT(CONCAT('field_', id), value)—— 键名不能是表达式 - 8.0 允许:
JSON_OBJECT(LOWER(col_name), col_value),但要注意返回类型可能被推断为 TEXT,必要时加CAST(... AS JSON) - 跨版本兼容写法:先用
CONCAT拼好键名变量,再传入JSON_OBJECT(@key1, @val1, @key2, @val2)
避免 SQL 注入和非法键名的处理方式
直接把用户输入拼进 JSON_OBJECT 的键位置(如 JSON_OBJECT(user_input, value))会导致语法错误甚至注入风险——键名若含双引号、反斜杠或控制字符,MySQL 解析会失败。
php版微信js-sdk支付接口类
php版微信js-sdk支付接口类
下载
- 安全做法:用
REPLACE(REPLACE(user_input, '"', '\"'), '\', '\\')预处理,再包裹双引号形成合法字符串字面量 - 更稳妥方案:先用
JSON_SET或JSON_INSERT构建基础对象,再逐个设值,例如:JSON_SET('{}', CONCAT('$.', @safe_key), @val) - 注意:MySQL 不校验键名是否符合 JSON 标准(如空格、点号),但某些下游系统(如 Node.js
JSON.parse)可能拒绝解析
与 JSON_ARRAYAGG 配合构建嵌套结构的典型陷阱
常见需求是把多行数据聚合成一个 JSON 对象数组,比如 SELECT JSON_OBJECT('id', id, 'name', name) FROM user 再套 JSON_ARRAYAGG。这里容易忽略聚合上下文和 NULL 处理。
- 若某行中
name为NULL,对应对象会丢失name字段(见第一条),不是"name": null -
JSON_ARRAYAGG(JSON_OBJECT(...))遇到任意输入行为NULL,整组聚合结果变NULL,需用WHERE col IS NOT NULL过滤,或用COALESCE(..., 'null')替换 - 性能提示:大结果集上慎用,
JSON_OBJECT+JSON_ARRAYAGG比纯字符串拼接慢不少,超 10 万行建议分页或应用层组装
实际用的时候,最常卡住的是键名合法性判断和 NULL 值静默丢弃——这两点不提前验证,查半天发现对象里少字段,却找不到源头。