一个表最多能建几个触发器
MySQL 允许对同一张表为每个触发事件(
INSERT、
UPDATE、
DELETE)分别定义
BEFORE和
AFTER两种时机的触发器,因此单表最多支持 6 个触发器:
BEFORE INSERT
AFTER INSERT
BEFORE UPDATE
AFTER UPDATE
BEFORE DELETE
AFTER DELETE超过这个数量再执行
CREATE TRIGGER会报错:
ERROR 1359 (HY000): Trigger already exists(注意:该错误码实际表示“同名触发器已存在”,但更常见的是因命名冲突或重复创建导致;真正超限会报
ERROR 1235 (42000): This version of MySQL doesn't yet support 'multiple triggers with the same action time and event for one table'—— 这在 5.7+ 已解除限制,但逻辑上限仍是 6)。
触发器命名必须全局唯一
MySQL 不允许同名触发器存在,哪怕在不同表上也不行。触发器名作用域是整个数据库(
SCHEMA),不是表级。这意味着: 不能有两个触发器都叫
tr_log_after_insert,哪怕一个在
users表、一个在
orders表 建触发器时若不显式指定名字,MySQL 不会自动生成;你必须写
CREATE TRIGGER xxx BEFORE INSERT ...,
xxx是必需字段 重命名触发器不可行,只能先
DROP TRIGGER IF EXISTS old_name,再重建
触发器中不能修改当前表
这是最容易踩的坑:
BEFORE或
AFTER触发器里,如果尝试对「正在被触发的同一张表」做
INSERT/
UPDATE/
DELETE,会直接报错:
ERROR 1442 (HY000): Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
典型误用场景:
在BEFORE INSERT ON orders中试图往
orders表插入一条日志记录 在
AFTER UPDATE ON users中又去
UPDATE users设置某个字段(比如
updated_at)
解决办法只有两个:
把需要写入的数据转存到另一张日志表(如orders_log),确保表名不同 改用应用层逻辑或定时任务补全,避开触发器内写本表
触发器不支持事务回滚中的自动清理
触发器本身运行在主语句的事务上下文中,但它执行的语句也会参与事务。问题在于:如果主语句最终
ROLLBACK,触发器里做的变更(比如往日志表插数据)也会一起回滚 —— 听起来合理?但隐患在于: 如果你在触发器里调用了存储过程,而该过程内部有
START TRANSACTION或
COMMIT,会直接报错:
ERROR 1305 (42000): SAVEPOINT does not exist或更常见的
Explicit or implicit commit is not allowed in stored function or trigger触发器无法感知主事务是否将要失败,也无法注册
ON ROLLBACK回调 想实现“不管主事务成败都要记日志”,只能用
INSERT DELAYED(已弃用)或外部消息队列,MySQL 原生不支持
所以别指望触发器能当可靠审计日志的兜底方案;真要强一致性,得靠应用层双写 + 本地消息表 + 补偿任务。
