必须同时在INSERT和UPDATE上创建触发器,因新商品入库或多次出库均可能首次跌破阈值;应使用BEFORE触发器直接读NEW字段判断并插入提醒表,避免SELECT查本表引发死锁或脏读,且阈值宜存于同一行。

触发器该写在库存表的 UPDATE 还是 INSERT 上
必须同时监听 INSERT 和 UPDATE,只写一个会漏预警。比如新商品入库(INSERT)时初始库存就低于阈值,或多次出库后(UPDATE)跌破阈值,两种场景都要捕获。
常见错误是只在 UPDATE 上写逻辑,结果新上架的低库存商品永远不进提醒表。
- MySQL 中用
CREATE TRIGGER ... BEFORE INSERT, UPDATE(注意:MySQL 不支持单语句触发多事件,需拆成两个触发器) - PostgreSQL 支持单触发器响应多事件:
AFTER INSERT OR UPDATE ON inventory - SQL Server 同样支持
FOR INSERT, UPDATE
判断库存是否低于阈值时,该查 NEW 行还是查全表
必须直接用触发器上下文中的 NEW(或 inserted、NEW ROW)字段判断,不能额外 SELECT 查询库存表本身——这会引发递归或死锁,尤其在 BEFORE 触发器里查本表还可能读到未提交旧值。
示例(MySQL):
IF NEW.stock_quantity < NEW.low_stock_threshold THEN INSERT INTO stock_alert (product_id, alert_time, current_stock) VALUES (NEW.product_id, NOW(), NEW.stock_quantity); END IF;
-
NEW.stock_quantity是本次操作后的新值,可信 - 别写
SELECT stock_quantity FROM inventory WHERE id = NEW.id—— 多余且危险 - 阈值最好存在同一行(如
low_stock_threshold字段),避免关联查询配置表
为什么不能用 AFTER 而必须用 BEFORE 插入提醒表
不是“不能用 AFTER”,而是 AFTER 在事务提交后才执行,如果库存更新事务中途失败回滚,提醒表却已插入脏数据,导致误报。
更稳妥的做法是用 BEFORE 触发器,在原事务内完成预警插入,确保原子性。
- MySQL / PostgreSQL:用
BEFORE INSERT OR UPDATE,直接操作NEW行并插入提醒表 - SQL Server:
INSTEAD OF不适用(会绕过原操作),应选AFTER但需加事务控制,或改用应用层补偿 - 若数据库不支持
BEFORE多事件,至少保证提醒表插入和主表更新在同一个显式事务中
提醒表设计不当会导致重复插入或漏告警
最常被忽略的是去重逻辑。同一商品库存反复在阈值附近波动(比如 5→4→5→3),可能连续触发多次插入,而业务只需要“首次跌破”提醒。
解决方法不是靠触发器内部加复杂状态判断,而是靠表结构约束 + 应用配合:
- 提醒表加唯一联合索引:
UNIQUE (product_id, DATE(alert_time))或按天分区去重 - 更推荐加状态字段:
status ENUM('pending', 'notified', 'cleared'),由下游服务消费后更新状态 - 避免在触发器里做
SELECT COUNT(*)判断是否已存在——高并发下仍可能重复 - 如果真要“首次跌破”,建议把判断逻辑移到应用层,触发器只负责发消息(如写 Kafka),由消费者做幂等
触发器适合轻量、确定性动作;一旦涉及状态机、去重、重试,它就不再是最佳载体。

















