本文目录导读:

实现PHP项目中的商品库存预警,核心思路是设置阈值 + 定时或实时检查 + 通知相关方。
下面我会分几个层级来讲解实现方案,从基础的数据库设计到中级的通知机制,再到高级的优化建议。
核心数据与逻辑
你需要一个合理的数据库结构来存储库存和阈值。
数据库表设计
假设你有一个商品表 products,通常需要以下关键字段:
-- 商品表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
sku VARCHAR(100) UNIQUE, -- 库存量单位
stock_quantity INT NOT NULL DEFAULT 0, -- 当前库存数量
low_stock_threshold INT NOT NULL DEFAULT 10, -- 低库存预警阈值
status TINYINT DEFAULT 1, -- 1:正常 2:预警 3:缺货
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
stock_quantity:实时更新,每次出库/入库都修改它。low_stock_threshold:每个商品可以单独设置,比如A商品低于5个预警,B商品低于50个预警。status:可以作为一个冗余字段,方便快速查询哪些商品处于预警状态,避免每次查询都做比较运算。
核心判断逻辑(PHP代码片段)
当发生订单出库、退货入库等操作时,更新库存并立即检查是否触发预警。
<?php
class InventoryService
{
private $db; // PDO连接
public function __construct($pdo)
{
$this->db = $pdo;
}
/**
* 出库操作并检查预警
* @param int $productId 商品ID
* @param int $quantity 出库数量
* @return array 返回状态信息
*/
public function decreaseStockAndCheckAlert(int $productId, int $quantity): array
{
// 1. 开始事务
$this->db->beginTransaction();
try {
// 2. 获取当前库存和阈值(使用行锁或乐观锁防止高并发超卖)
$sql = "SELECT stock_quantity, low_stock_threshold FROM products WHERE id = ? FOR UPDATE";
$stmt = $this->db->prepare($sql);
$stmt->execute([$productId]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$product) {
throw new \Exception('商品不存在');
}
$currentStock = (int)$product['stock_quantity'];
$threshold = (int)$product['low_stock_threshold'];
// 3. 检查库存是否充足
if ($currentStock < $quantity) {
throw new \Exception('库存不足,当前库存:' . $currentStock);
}
// 4. 更新库存
$newStock = $currentStock - $quantity;
$updateSql = "UPDATE products SET stock_quantity = ? WHERE id = ?";
$updateStmt = $this->db->prepare($updateSql);
$updateStmt->execute([$newStock, $productId]);
// 5. 判断是否需要预警
$alertInfo = $this->checkAndTriggerAlert($productId, $newStock, $threshold);
// 6. 提交事务
$this->db->commit();
return [
'success' => true,
'new_stock' => $newStock,
'alert_triggered' => $alertInfo['triggered'],
'message' => $alertInfo['message']
];
} catch (\Exception $e) {
$this->db->rollBack();
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* 检查并触发预警
*/
private function checkAndTriggerAlert(int $productId, int $stock, int $threshold): array
{
$triggered = false;
$status = 1; // 正常
$message = '';
if ($stock <= 0) {
$status = 3; // 缺货
$triggered = true;
$message = '严重预警:商品 ID ' . $productId . ' 已缺货!';
} elseif ($stock <= $threshold) {
$status = 2; // 低库存预警
$triggered = true;
$message = '预警:商品 ID ' . $productId . ' 库存低于阈值(当前:' . $stock . ',阈值:' . $threshold . ')';
}
// 更新商品状态(可选,但推荐)
$updateStatusSql = "UPDATE products SET status = ? WHERE id = ?";
$stmt = $this->db->prepare($updateStatusSql);
$stmt->execute([$status, $productId]);
return [
'triggered' => $triggered,
'message' => $message
];
}
}
关键点:
- 行锁 (
FOR UPDATE):在高并发下防止超卖,确保扣减库存和检查逻辑是原子性的。 - 阈值可配置:每个商品都应有独立的
low_stock_threshold。
获取预警商品列表
哪些商品需要补货?后台管理页面经常需要这个列表。
<?php
/**
* 获取所有需要补货的商品列表
* @param PDO $pdo
* @return array
*/
function getLowStockAlerts(PDO $pdo): array
{
$sql = "SELECT id, name, sku, stock_quantity, low_stock_threshold
FROM products
WHERE stock_quantity <= low_stock_threshold
ORDER BY (stock_quantity - low_stock_threshold) ASC";
$stmt = $pdo->query($sql);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 使用示例
$lowStockProducts = getLowStockAlerts($pdo);
foreach ($lowStockProducts as $product) {
echo "商品:" . $product['name'] . ",当前库存:" . $product['stock_quantity'] . ",阈值:" . $product['low_stock_threshold'] . PHP_EOL;
}
优化建议: 在这个查询的 stock_quantity 和 low_stock_threshold 字段上建立复合索引,可以极大提升查询性能。
ALTER TABLE products ADD INDEX idx_stock_alert (stock_quantity, low_stock_threshold);
通知机制(如何让人知道)
光查出数据还不够,你需要主动通知运营或仓库人员。
实时通知(在出库/入库操作时触发)
在 decreaseStockAndCheckAlert 方法的最后,如果发现预警,可以:
- 日志记录:写入
inventory_alert_logs表。 - 消息队列:向 RabbitMQ / Redis 列表推送一条任务,由异步消费者去处理发送邮件/短信。
- WebSocket:后台管理界面实时弹出通知(适合后台管理员场景)。
定时任务通知(适合不需要实时响应的场景)
使用 Linux Crontab 或 Windows 任务计划 定时执行一个 PHP 脚本。
Crontab 示例(每天上午9点检查一次):
0 9 * * * /usr/bin/php /var/www/html/cron/check_stock_alert.php
PHP 脚本示例 (check_stock_alert.php):
<?php
// 引入数据库连接和发送邮件的类
$alertProducts = getLowStockAlerts($pdo);
if (!empty($alertProducts)) {
$subject = '【库存预警】系统发现 ' . count($alertProducts) . ' 个商品需要补货';
$body = "以下是库存不足的商品清单:\n\n";
foreach ($alertProducts as $p) {
$body .= "商品: {$p['name']} (SKU: {$p['sku']}) | 当前库存: {$p['stock_quantity']} | 阈值: {$p['low_stock_threshold']}\n";
}
// 发送邮件或企业微信/钉钉机器人消息
// sendEmail('admin@yourstore.com', $subject, $body);
// sendWeComRobot('YOUR_WECOM_KEY', $subject, $body);
}
echo "检查完成,发现 " . count($alertProducts) . " 个预警商品。\n";
通知方式建议(按重要程度排列):
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 邮件 | 批量、非紧急 | 成本低,信息详细 | 可能有延迟,容易被忽略 |
| 短信 | 缺货、严重预警 | 及时性强 | 成本高,信息不宜过长 |
| 企业微信/钉钉/飞书机器人 | 内部团队协作 | 接收率高,支持富文本 | 需要公司使用相应IM工具 |
| 系统后台站内信/通知中心 | 内部管理系统 | 与其他功能集成性好 | 依赖用户登录系统 |
高级优化与最佳实践
-
缓存库存值(Redis)
- 对于高访问量的商品,库存每次从数据库读可能太慢。
- 方案:库存主要存在 Redis 里(
product_stock:123),出库时用 Redis 的DECR原子操作,然后异步同步回 MySQL。 - 预警检查:可以在 Redis 里也存储一个阈值,触发
DECR后比较,如果低于阈值,立即通知消息队列。
-
记录库存变更日志
- 每次修改库存(增、减、手动调整)都应该记录到
stock_movements表。 - 作用:用于审计、追查“谁导致了预警”、分析历史库存趋势。
- 每次修改库存(增、减、手动调整)都应该记录到
-
分级预警
- 不仅设置一个阈值,可以设置多个等级。
warning_threshold= 50 (黄色预警,提示注意)danger_threshold= 10 (红色预警,立即补货)out_of_stock= 0 (严重,不能卖)
-
在订单流程中植入
- 用户在后台或前台将商品加入购物车时,如果库存低于阈值,在商品页面上显示“库存紧张” 标签,这可以提升用户体验,并刺激用户尽快下单。
- 实现:在展示商品详情时,执行一次比较。
一个可用的库存预警方案需要这三步:
- 数据准备:为每个商品配置不同的
low_stock_threshold,并设计好数据库索引。 - 逻辑触发:在每次库存变动后立即判断,并更新商品状态(正常/预警/缺货)。
- 通知落地:根据业务紧急程度,选择邮件、短信、IM机器人或系统内部通知。
如果你是开发中小型项目,从第二部分的定时任务 + 邮件通知开始做比较简单;如果是大型电商项目,建议直接上消息队列 + WebSocket + 实时日志的方案。