MySQL 8.0使用JSON函数报错Invalid JSON text时如何快速找出非法数据行?

作者:袖梨 2026-07-12
JSON_VALID()可批量筛查非法JSON值,返回0表示语法错误,不抛异常;查整表用WHERE JSON_VALID(col)=0,空值需单独判断;建议加CHECK约束并避免空字符串入库。

用JSON_VALID()批量筛查非法JSON值

直接在WHERE里套JSON_VALID()就能筛出所有非法行,它返回0就代表JSON语法错误,不抛异常、不中断查询。比逐条试INSERT或SELECT更省事。

  • 查整张表:SELECT id, json_col FROM table_name WHERE JSON_VALID(json_col) = 0;
  • 查空字符串或NULL:SELECT id, json_col FROM table_name WHERE json_col = '' OR json_col IS NULL;(注意:JSON_VALID('')返回0,JSON_VALID(NULL)返回NULL)
  • 如果字段允许NULL但业务上不该为空,建议加CHECK (json_col IS NOT NULL AND JSON_VALID(json_col))约束(MySQL 8.0.16+支持)

报错信息里“at position 0”通常意味着什么

位置0出错,基本等于“连JSON的边都没摸到”,常见于:空字符串''、纯空白(空格/换行)、'null'(字符串不是JSON字面量)、或根本没传值(MyBatis-Plus未设默认值导致字段为'')。

  • JSON_VALID('') → 0,JSON_VALID('null') → 1(合法),JSON_VALID("null") → 0(单引号非法)
  • Java侧用Jackson序列化时,确保对象非空再转字符串;若可能为空,显式写成{}[],别留""
  • MyBatis-Plus中,给JSON字段加@TableField(fill = FieldFill.INSERT)并配合自动填充逻辑,避免入库空串

结合Last_SQL_Error反向定位复制或导入失败源

如果是主从复制卡住,或者LOAD DATA报错,Last_SQL_Error里的“position 0”提示要立刻查对应SQL的VALUES部分——大概率是某一行的JSON字段被拼成了'''{...'(少结尾括号)。

  • 执行SHOW BINLOG EVENTS IN 'xxx' FROM yyy LIMIT 1(从Exec_Master_Log_Pos往前推)找原始SQL
  • 把报错SQL复制出来,在本地用SELECT JSON_VALID(?), ?逐个参数测试,快速锁定哪个参数是空或畸形
  • 特别注意:从库版本低于主库时,JSON_VALID()行为一致,但CAST(... AS JSON)可能因sql_mode差异提前失败

别依赖应用层校验,数据库约束才是最后一道防线

开发时本地测不出问题,上线后突然报错,往往是因为测试数据没覆盖空值路径。靠代码判断StringUtils.isNotBlank()不够,MySQL对JSON的校验更严格。

  • 建表时直接加CHECK:feature_data JSON CHECK (JSON_VALID(feature_data) AND feature_data != '')
  • 避免用TEXT存JSON再手动解析——失去自动校验,也丧失->操作符和JSON索引能力
  • 如果已有脏数据,先用UPDATE ... SET json_col = COALESCE(NULLIF(json_col, ''), '{}') WHERE JSON_VALID(json_col) = 0;兜底,再加约束
真正麻烦的不是语法错误,而是那些JSON_VALID()返回1、但后续JSON_EXTRACT()取不到值的“合法垃圾”——比如{"name": null}{}。这类问题得靠业务逻辑层约定,数据库管不了语义。

相关文章

精彩推荐