json_extract在触发器中需前置json_valid校验,用->>或json_unquote去引号,数字字段建议显式cast,json比对须提取路径后类型一致比较。

触发器里直接用 JSON_EXTRACT 提取 JSON 字段局部值是可行的,但必须绕过类型校验和空值陷阱,否则触发器会中断执行。
为什么 JSON_EXTRACT(NEW.json_col, '$.key') 在触发器里常报错
MySQL 5.7 要求 JSON_EXTRACT 的第一个参数必须是合法 JSON 类型值,而 NEW.json_col 实际上是 TEXT 或 VARCHAR 类型(即使列定义为 JSON,在触发器上下文中也可能未被自动强转)。一旦字段为空、含非法字符或只是普通字符串,就会触发 Invalid JSON text 错误,导致整个触发器失败。
-
JSON_VALID(NEW.json_col)必须前置判断,不能省略 - 若列定义为
JSON但内容来自旧应用或迁移数据,仍可能存非 JSON 值(如'null'字符串而非真正的NULL) -
JSON_EXTRACT对路径错误或键不存在不报错,但返回NULL;若后续赋值给非空列,会引发插入失败
JSON_EXTRACT 返回值带引号,直接赋值会出问题
JSON_EXTRACT 返回的是 JSON 类型值,比如 "john"(带双引号),不是字符串 john。如果把它直接赋给 VARCHAR 列,MySQL 5.7 默认会保留引号,导致业务层看到的是 "john" 而非预期的 john。
- 必须用
JSON_UNQUOTE(JSON_EXTRACT(...))去掉外层引号 - 或者改用
->>操作符(等价于JSON_UNQUOTE(JSON_EXTRACT(...))),写法更短:NEW.json_col->>'$.name' - 对数字字段(如
age),JSON_EXTRACT返回的是 JSON 数字,MySQL 会隐式转为整数,但建议显式CAST(... AS UNSIGNED)避免边界异常(如-0、科学计数法)
UPDATE 触发器中安全比对 JSON 内部字段是否变更
不能写 OLD.json_col != NEW.json_col —— 这是字符串比较,顺序、空格、换行都影响结果,且无法识别语义等价的 JSON(如 {"a":1} 和 {"a": 1})。
- 应提取具体路径并分别比对:
JSON_UNQUOTE(OLD.json_col->>'$.status') != JSON_UNQUOTE(NEW.json_col->>'$.status') - 注意两边都用
->>或都用JSON_UNQUOTE(JSON_EXTRACT()),保持类型一致 - 若字段可能为
NULL,需用IS NULL/IS NOT NULL显式判断,避免NULL != 'x'返回NULL(即 false) - 数组或嵌套对象变更监控不推荐在触发器里做——性能差且逻辑复杂;只盯关键标量字段(
status、price、updated_by)更实际
BEFORE INSERT/UPDATE 中解析 JSON 并填充生成列或普通列
典型场景:用户提交 profile JSON,想自动拆出 nickname 和 email 存到对应列,便于索引和查询。
- 必须包裹在
IF JSON_VALID(NEW.profile) THEN ... END IF;中 -
SET NEW.nickname = NEW.profile->>'$.nickname';是最简写法;若路径可能缺失,加IFNULL(..., '')防止NULL写入非空列 - 不要在触发器里对本表做
SELECT或UPDATE—— 所有操作只能基于NEW和OLD行数据 - 大 JSON(>4KB)频繁解析会影响触发器性能;若字段更新频率低但解析开销高,可考虑延迟处理(如通过应用层或异步任务)











