核心是库存变动即触发预警:mysql用after update触发器兜底,yii在aftersave中嵌入业务级预警逻辑,redis防重+消息队列解耦通知,确保实时、准确、可扩展。

Yii 搭建库存预警系统,预警触发的核心在于实时性、准确性与可扩展性。它不能只靠定时扫描“查漏补缺”,而要让库存变动本身成为预警的起点——即在每次库存更新(入库、出库、调拨)时,立即判断是否跌破阈值,并同步执行通知或记录动作。
一、数据库层:用触发器做第一道防线
在 MySQL 中为库存表添加 AFTER UPDATE 触发器,是最轻量、最可靠的底层触发方式。它不依赖应用逻辑,即使 Yii 应用宕机或代码跳过校验,只要数据变更走的是 SQL 更新,预警逻辑就依然生效。
- 确保库存表含 current_stock 和 min_threshold 字段(建议分表:products + inventory + alert_rules,便于多维度配置)
- 触发器逻辑需区分“仅数量变化”和“阈值被修改”,避免误触发
- 推荐写法:当
NEW.current_stock 且 <code>OLD.current_stock > NEW.min_threshold(即首次跌破),才插入预警记录到stock_alerts表
二、应用层:在 Yii ActiveRecord 中嵌入预警钩子
触发器负责兜底,但业务级预警(如按分类推送、关联采购单、标记紧急等级)需由 Yii 控制。可在 Inventory 模型的 afterSave() 方法中实现:
- 检查
$this->isAttributeChanged('current_stock'),确认是库存变动而非其他字段更新 - 读取对应商品的预警规则(从
alert_rules表或缓存中获取) - 若触发条件成立,调用
AlertService::send($this)发送站内信、邮件或写入消息队列 - 避免在
afterSave中做耗时操作(如发邮件),应投递至 RabbitMQ 或 Redis 队列异步处理
三、高并发防护:防止重复预警与超卖干扰
大促或批量出入库场景下,同一商品可能被高频更新,导致多次触发预警。需加一层去重控制:
- 预警记录表增加唯一联合索引:
(product_id, DATE(alert_time)),限制每日每品最多一条预警 - 使用 Redis SETNX 设置临时锁键,如
alert:lock:1024:20260817,有效期 5 分钟,避免同一商品当天重复告警 - 库存扣减必须走事务 + 乐观锁(version 字段)或 Redis 原子 DECR,否则预警可能基于“脏读”库存,失去意义
四、通知机制:解耦才能稳定
预警触发 ≠ 立即发邮件。Yii 应用主线程应快速返回,把通知交由后台消费者执行:
- 预警记录写入数据库后,立刻向 RabbitMQ 发送消息:
{ "alert_id": 123, "product_id": 1024, "type": "low_stock" } - 独立的 console 命令(如
yii alert/consume)监听队列,执行具体通知逻辑 - 支持多通道:邮件用 SwiftMailer,站内信写入
user_notifications表,企业微信/钉钉调用 Webhook API
不复杂但容易忽略:预警不是“发现少了才提醒”,而是“让所有人知道为什么少、该谁处理、下一步做什么”。Yii 的优势在于模型层与事件系统的天然契合,把预警做成可监听、可订阅、可回溯的动作流,比堆砌弹窗和邮件更可持续。











