能做,但必须用BEFORE INSERT触发器,且校验靠SIGNAL中断、标准化靠SET NEW.field赋值——缺一不可;AFTER INSERT中NEW只读,SET会报错,数据已落盘无法修改。

能做,但必须用 BEFORE INSERT 触发器,且校验靠 SIGNAL 中断、标准化靠 SET NEW.field 赋值——这两步缺一不可。
为什么只能用 BEFORE INSERT,不能用 AFTER INSERT
AFTER INSERT 中的 NEW 是只读的,执行 SET NEW.email = 'x@y.com' 会直接报错:ERROR 1362 (HY000): Updating of NEW row is not allowed in after trigger。此时数据已落盘,改也无效;而 BEFORE INSERT 的 NEW 是可写临时行对象,SET 操作直接影响最终入库值。
常见误操作:
- 把格式化逻辑写在
AFTER INSERT里,结果字段没变,还报错 - 以为
UPDATE表能补救,但事务已提交,应用层可能已认为成功
校验失败必须用 SIGNAL,不能只写 IF + SELECT
SELECT '邮箱错误' 这类语句完全不中断插入流程,数据照常入库。真正起效的是 SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'email 格式不合法'。
注意细节:
-
MESSAGE_TEXT最长 128 字符,建议关键字段名前置(如'phone 长度不足11位') - 多个校验项必须拆成独立
IF ... END IF;,MySQL 遇到第一个SIGNAL就终止,后续不执行 - 字段允许
NULL时,得先判断:IF NEW.email IS NOT NULL THEN ... END IF;,否则NULL REGEXP 'xxx'返回NULL(非FALSE),条件不触发
标准化处理要小心字段约束和 MySQL 版本
格式化不是写个 SET 就完事,得看字段定义和函数支持情况。
典型陷阱:
-
SET NEW.email = LOWER(TRIM(NEW.email))看似安全,但如果email字段是NOT NULL且无默认值,而清洗后变成空字符串,插入会失败 -
REGEXP_REPLACE(NEW.phone, '[^0-9]', '')只在 MySQL 8.0+ 支持,低版本得用REPLACE套嵌或放弃 - 日期字段慎用
NOW()填充,默认含时分秒;要用CURDATE()或DATE(NOW())避免精度干扰 - 批量插入(如
INSERT INTO ... SELECT)可能绕过触发器,得确认账号有TRIGGER权限,且客户端未禁用
真正容易被忽略的是:触发器不是“万能过滤网”。它对 LOAD DATA INFILE、某些 INSERT ... ON DUPLICATE KEY UPDATE 场景、以及 MySQL 5.7 及更早版本的正则锚点(^/$)支持都不稳定。上线前务必用真实数据流测一遍,别只跑单条 INSERT。


















