不能靠触发器保证主表与明细表数据一致,必须用应用层显式事务+幂等更新兜底;mysql 5.7+禁止触发器中修改自身表,仅允许before update中赋值new字段;跨表同步易出错,推荐异步队列方案。

不能靠触发器保证主表与明细表数据一致——它只在单点、低频、无并发写入的场景下“看起来”有效;真实业务中,必须用应用层显式事务+幂等更新兜底。
BEFORE UPDATE里改NEW字段是唯一安全写法
MySQL 5.7+ 明确禁止在触发器中对触发它的表执行 UPDATE、INSERT 或 DELETE。比如你在 orders 表上建了 AFTER UPDATE 触发器,里面写 UPDATE orders SET status = 'done',会直接报错:ERROR 1442。
- 合法操作只有:在
BEFORE UPDATE中给NEW.status、NEW.updated_at赋值,影响即将写入的行 - 非法操作包括:
UPDATE orders SET counter = counter + 1 WHERE id = NEW.id(哪怕加了WHERE也不行) - 想自动维护订单总金额?别在触发器里查
order_items求和再写回orders.total_amount——这会拖慢主表写入,且高并发时结果不可靠
AFTER INSERT/UPDATE里跨表同步极易出错
很多人在 AFTER INSERT 触发器里写 INSERT INTO order_summary SELECT ... FROM order_items WHERE order_id = NEW.order_id,看似合理,实则埋雷:
- 子查询没索引?每插入一行就全表扫一次
order_items,QPS 上百就卡住 - 明细表有延迟或未提交的数据?触发器读到的是旧快照,同步结果不准
- 批量插入(如
INSERT INTO orders VALUES (), ())默认跳过所有触发器,同步直接失效 - 如果
order_summary同时被其他路径写入(比如后台统计任务),触发器更新会覆盖或冲突
真正能落地的一致性方案只有两种
触发器不是一致性协调者,它没有事务隔离能力,也不能回滚主操作。所谓“同步”,本质是把风险从应用层转移到数据库层,但没消除。
- 强一致性场景(如支付订单+明细):应用层开启事务 → 插入
orders→ 插入多条order_items→ 更新orders.total_amount→ 统一提交;任一环节失败,全部回滚 - 最终一致性场景(如报表汇总):触发器只往
sync_queue表插入变更记录(轻量、快),由独立消费者进程异步拉取、去重、聚合、写入order_summary;失败可重试,不阻塞主链路 - 别信“自动同步”——
INSERT IGNORE、REPLACE INTO、ORM 的bulk_create全部绕过触发器;你写的逻辑,在真实生产流量里大概率不生效
最常被忽略的点:触发器函数返回 NULL 会跳过后续操作,返回 OLD 或 NEW 才生效;而 MySQL 默认返回 NULL,不显式写 SELECT NEW.*; 或 SET NEW.x = ...;,整个触发器等于没写。











