mysql触发器中判断null必须用is null,不可用= null或!字段;阻止null插入需用signal sqlstate '45000';not null约束比触发器更高效,触发器仅适用于复杂业务校验。

MySQL 触发器里怎么判断 NEW.column_name 是 NULL
直接用 IS NULL,别用 = NULL —— 后者永远返回 UNKNOWN,条件不成立。触发器中对空值的判断必须显式写成 IF NEW.phone IS NULL THEN 这种形式。
常见错误是写成 IF NEW.phone = NULL 或 IF !NEW.phone,这两种都无效,会导致非空检查完全失效。
-
NEW是 INSERT/UPDATE 触发器里的只读引用,代表即将插入或修改的新行数据 - 对
TEXT、JSON、BLOB类型字段,IS NULL依然可靠;但空字符串''和NULL是两回事,需分开处理 - 如果业务要求“不允许空字符串 + 不允许 NULL”,得额外加
OR NEW.email = ''
INSERT BEFORE 触发器中抛出错误的正确写法
MySQL 5.7+ 支持用 SIGNAL SQLSTATE 主动报错中断插入,这是唯一能阻止 NULL 写入的方式。不能靠 SELECT 'error' 或 INSERT INTO error_log —— 那些不会终止当前语句。
示例:阻止 user_name 为空
DELIMITER $$
CREATE TRIGGER check_user_name_not_null
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
IF NEW.user_name IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'user_name cannot be NULL';
END IF;
END$$
DELIMITER ;
-
SQLSTATE '45000'是通用用户定义错误码,客户端能捕获到ERROR 1644 - 别用
RAISE(PostgreSQL 语法)或THROW(SQL Server),MySQL 不认 - UPDATE 触发器也要做同样检查,否则绕过 INSERT 直接 UPDATE 仍可写入 NULL
哪些字段不适合用触发器做非空校验
外键字段、自增主键、有默认值的字段,通常不需要触发器干预 —— 数据库层已有约束机制更高效、更明确。
-
NOT NULL约束本身就能拦截 NULL 插入,比触发器快且无需额外逻辑 - 如果字段已声明
NOT NULL,再加触发器纯属冗余,还可能掩盖建表疏漏 - 时间戳字段如
created_at推荐用DEFAULT CURRENT_TIMESTAMP,而不是在触发器里赋值 - 触发器适合校验“业务级非空”,比如
id_card字段允许为 NULL,但一旦提供就必须是 18 位,这种复合逻辑才值得上触发器
触发器校验和应用层校验冲突怎么办
以数据库为准。触发器失败时,应用层收到的是 MySQL 错误,不是自定义提示。如果应用没处理 ERROR 1644,就会看到模糊的“Unknown error”。
- 后端代码里要明确 catch
SQLSTATE 45000并转成用户友好的提示,比如“身份证号不能为空” - 别在触发器里拼接中文错误信息传给前端——编码、长度、转义都容易出问题
- ORM 框架(如 Django ORM、MyBatis)通常不感知触发器报错,需手动检查异常类型
- 测试时容易漏掉:用
INSERT ... SELECT批量插入时,触发器仍生效,但错误可能只报第一条,后续行被跳过
SIGNAL 报错的堆栈几乎不带上下文。真要防 NULL,优先用 NOT NULL + 默认值 + 应用层预检,触发器只兜底最特殊的业务场景。










