MySQL触发器对批量INSERT天然逐行处理,每次仅访问当前行NEW值,无法跨行校验;应使用唯一索引配合INSERT IGNORE等语句保障数据一致性,避免在触发器中查询同批数据或依赖变量共享。

触发器对批量INSERT天然就是逐行处理
MySQL 5.7 不支持语句级触发器,FOR EACH ROW 是强制的、不可省略的语法。哪怕你写 INSERT INTO t VALUES (1,'a'),(2,'b'),(3,'c'),也会触发三次 BEFORE INSERT,每次只看到当前行的 NEW 值——上一行的 NEW.email 在下一次触发时已不可见。
不能跨行校验,但能改写当前行字段
NEW 在 BEFORE INSERT 中可读可写,适合做单行补全或标准化,比如自动填充时间、转小写、截断超长字符串。但以下操作必须避免:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 在触发器里
SELECT COUNT(*) FROM users WHERE email = NEW.email:只能查已有数据,查不到同批其他待插入行 - 用
SELECT查询其他表(如黑名单表):批量插入时会变成 N 次查询,性能雪崩 - 试图用变量暂存前一行值:MySQL 触发器不共享变量上下文,每次触发都是全新作用域
重复数据和整批一致性得靠约束或应用层
触发器无法实现“同一批中不允许两个相同 email”这种校验。真正可靠的做法是:
- 建唯一索引:
ALTER TABLE users ADD UNIQUE KEY uk_email (email) - 用
INSERT IGNORE或INSERT ... ON DUPLICATE KEY UPDATE处理冲突 - 如果业务要求“整批全过或全拒”,必须在应用层先
SELECT检查这批数据是否全部合法,再执行插入;或封装进存储过程中用事务控制
容易被忽略的生效边界
LOAD DATA INFILE 和 REPLACE 也会激活 BEFORE INSERT 触发器,且同样是逐行触发。但 INSERT ... SELECT 中的源表数据不会触发目标表的触发器——触发只发生在最终写入目标表的那一刻。另外,SIGNAL 报错会导致整条批量语句回滚,不是只跳过当前行。

















