JSON_VALID()返回1(有效)、0(无效)或NULL(参数为NULL),仅校验JSON语法合法性,不检查语义;严格遵循RFC 7159,拒绝未转义控制字符;推荐配合CHECK约束使用。

JSON_VALID() 返回 0 或 1,不是布尔值
JSON_VALID() 函数不返回 TRUE/FALSE,而是返回整数 1(有效)或 0(无效),空值时返回 NULL。这点容易在条件判断中出错,比如写成 WHERE JSON_VALID(col) = TRUE 会漏掉 NULL 行,且语义不严谨。
实际使用建议:
- 用
JSON_VALID(col) = 1明确匹配有效情况 - 用
JSON_VALID(col) IS NULL单独处理空值(注意:空字符串''也不合法,JSON_VALID('')返回0) - 避免与
IF()或CASE混用时忽略NULL分支,例如:CASE WHEN JSON_VALID(col) THEN 'valid' ELSE 'invalid' END会让NULL落入ELSE,但语义上它既不是 valid 也不是 invalid
字段内容含换行、制表符或 Unicode 控制字符时可能误判为无效
MySQL 的 JSON_VALID() 对 JSON 字符串的解析严格遵循 RFC 7159,不接受未转义的换行符
、回车
、制表符 ,也不接受 U+0000–U+001F 范围内的控制字符(除非正确转义为 uXXXX)。
常见陷阱:
- 从日志、HTTP 请求体或富文本字段导入的 JSON 常含原始换行,
JSON_VALID('{"msg":"hello world"}')返回0 - 前端 JavaScript 用
JSON.stringify()生成的字符串是合规的,但后端拼接或模板渲染时若未转义,极易引入非法字符 - 用
REPLACE(col, ' ', '\n')不能解决问题——因为反斜杠本身需被 JSON 解析器识别,而 MySQL 不在JSON_VALID()前自动做字符串转义
真正可行的做法是:在入库前由应用层清理或转义,或改用 JSON_SET() / JSON_OBJECT() 等函数构造 JSON,而非拼接字符串。
JSON_VALID() 无法检测语义错误,只校验语法
该函数只检查字符串是否符合 JSON 语法规则,不关心业务含义。比如以下全是 JSON_VALID() 返回 1 的合法 JSON:
SELECT JSON_VALID('{"id": 1, "name": null}'); -- ✅ 合法(null 是合法值)
SELECT JSON_VALID('{"price": "99.99"}'); -- ✅ 合法(字符串型数字)
SELECT JSON_VALID('[1,2,3,null,"abc"]'); -- ✅ 合法(数组含混合类型)
这意味着:
- 数值写成字符串(如
"123")、布尔写成小写字符串(如"true")不会被拦截 - 缺少必填字段、字段类型与业务约定不符等问题,
JSON_VALID()完全无感 - 若需结构校验(如“必须含
user_id且为整数”),得配合JSON_CONTAINS_PATH()、JSON_TYPE()和CAST()手动组合判断
在 INSERT/UPDATE 中用 CHECK 约束比手动调用更可靠
如果目标是阻止非法 JSON 写入,靠应用层或触发器里加 JSON_VALID() 判断并不保险——绕过 ORM、直连执行 SQL、批量导入等场景都可能跳过校验。
MySQL 8.0.16+ 支持对 JSON 列直接定义 CHECK 约束:
ALTER TABLE logs
ADD COLUMN payload JSON,
ADD CONSTRAINT chk_payload_valid
CHECK (JSON_VALID(payload));
这样任何插入或更新操作都会被引擎级拦截,错误信息明确为:Check constraint 'chk_payload_valid' is violated.
注意点:
- 已有数据需先清理,否则
ADD CONSTRAINT会失败 - 该约束对
NULL默认放行(因JSON_VALID(NULL)返回NULL,而 CHECK 中NULL视为通过),如需禁止空值,额外加payload IS NOT NULL - 旧版本 MySQL(JSON_VALID() 方案,但稳定性差一截
最易被忽略的是:CHECK 约束仅作用于列值本身,不递归验证嵌套对象里的子字段是否符合业务规则——那得靠应用层或存储过程兜底。











