insert触发器只能用new,delete触发器只能用old,update触发器两者皆可用;new仅在before中可修改,字段名必须严格匹配表定义且区分大小写,否则静默返回null或报错。

只能用 OLD 和 NEW 直接点字段名访问,不是变量、不能声明、不能赋值,也不是函数返回值——它们是 MySQL 在触发上下文中自动提供的只读伪记录。
哪些操作能用 OLD?哪些能用 NEW?
这是硬性限制,错一个就报错:
-
INSERT触发器:只有NEW可用,用OLD.id会直接报ERROR 1363: There is no OLD row in on INSERT trigger -
DELETE触发器:只有OLD可用,用NEW.name报NEW is not available in DELETE triggers -
UPDATE触发器:OLD和NEW都可用,且仅在BEFORE UPDATE中允许修改NEW字段
字段名写错不会报语法错,但会静默返回 NULL
MySQL 不校验字段是否存在,直到触发时才出问题。常见坑点:
- 表字段是
user_name,却写成OLD.username或OLD.USER_NAME→ 返回NULL,难排查 - 字段含空格或关键字(如
order status),没加反引号 →ERROR 1064 - 建表时用了双引号定义大小写敏感字段(如
"Name"),触发器里也得写OLD."Name" - 不确定字段名?先执行
DESCRIBE your_table确认真实拼写
比较新旧值时,NULL 处理最容易翻车
OLD.status != NEW.status 在任一端为 NULL 时结果恒为 NULL(即 false),条件永远不成立。必须用空值安全比较:
- 推荐写法:
NOT (OLD.status NEW.status)(是 MySQL 的空值安全等于) - 手动拆解也行:
(OLD.status IS NULL) != (NEW.status IS NULL) OR OLD.status != NEW.status - 别用
CONCAT(OLD.content, ' updated')处理TEXT字段——MySQL 5.7 某些版本会返回NULL,不是OLD失效,而是大字段上下文异常
BEFORE 还是 AFTER?改 NEW 值必须选对时机
NEW 字段只在 BEFORE 阶段可修改,AFTER 里改了也白改:
-
BEFORE INSERT:可设NEW.created_at = NOW(),用于填充默认值 -
BEFORE UPDATE:可设NEW.updated_at = NOW(),影响即将写入的数据 -
AFTER UPDATE:NEW.updated_at已落盘,再赋值无意义,还会报Can't update table in stored function/trigger - 不确定触发器类型?用
SHOW CREATE TRIGGER trigger_name看开头是BEFORE还是AFTER
真正容易被忽略的是:你看到日志里某字段值为空,第一反应常是“OLD 没拿到”,但大概率是字段类型为 TEXT 或 BLOB,加上函数调用(比如 CONCAT)导致上下文处理异常,而不是触发器机制失效。











