绝大多数情况下不该用触发器,应优先写在应用层;仅限审计字段填充、状态流转校验、跨表约束等必须由数据库原子性保证的场景,且需注意跨库限制与调试运维成本。

触发器在 MySQL 里到底该不该用
绝大多数情况下,优先写在应用层,而不是用触发器。MySQL 触发器不是“业务逻辑的备份方案”,它本质是数据库层面的耦合钩子,一旦滥用,排查难、测试难、迁移难——尤其是当应用要分库分表或换数据库时,触发器直接失效或行为不一致。
哪些场景下触发器确实比应用层更可靠
仅限于 必须由数据库原子性保证、且无法被应用绕过的操作,比如:
• AFTER INSERT 自动填充审计字段(如 created_at、created_by),前提是这些字段不允许应用传入
• BEFORE UPDATE 强制校验状态流转(如订单只能从 'pending' → 'confirmed',不能跳到 'cancelled')
• 跨表约束类逻辑(如库存扣减失败时自动回滚主表插入),但要注意:MySQL 的触发器不能跨库操作,且不能调用存储过程以外的外部服务
触发器 vs 应用层:几个关键差异点
事务可见性不同 :触发器和主 SQL 在同一事务中执行,能读到未提交的数据;而应用层逻辑通常在事务外或分步提交,容易出现竞态。
调试成本悬殊 :SHOW TRIGGERS 查得到定义,但断点、日志、单测几乎为零;应用层可打日志、mock 依赖、走完整测试链路。
性能影响隐蔽 :一个 BEFORE INSERT 触发器若调用了 SELECT …… FOR UPDATE,可能把简单插入变成锁等待热点;应用层至少能异步化或加缓存。
错误处理粒度差:触发器内抛错会直接中断整个语句,返回类似 ERROR 1422 (HY000): Explicit or implicit commit is not allowed in stored function or trigger,而应用层可以重试、降级、记录补偿任务。
一个典型踩坑例子:用触发器同步冗余字段
比如在 orders 表插入后,用触发器往 order_summary 表写统计值。问题来了:
• 如果触发器里写了 INSERT INTO order_summary …… ON DUPLICATE KEY UPDATE,但 order_summary 没有主键或唯一索引,整条语句静默失败
• 若后续应用直接 UPDATE orders,触发器不会触发,order_summary 就彻底不一致
• 更糟的是,mysqldump 默认不导出触发器,从备份恢复后逻辑丢失,没人发现
真正需要强一致性的地方,宁可用应用层的“双写 + 校验任务”,也别依赖触发器兜底。数据库该专注数据持久、隔离、崩溃恢复,而不是替业务做决策。