本文目录导读:

在PHP项目中实现库存预警,核心思路是在业务逻辑的关键节点(如下单、入库、出库)检查库存数量,并与设定的预警阈值进行比较,当低于阈值时触发通知。
下面我将从数据表设计、核心逻辑实现、预警方式和最佳实践四个方面,为你提供一个完整的实现方案。
数据库表设计
你需要一个基础的库存表和预警规则表。
产品库存表 (products 或 inventory)
CREATE TABLE `products` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `sku` VARCHAR(100) UNIQUE NOT NULL, -- 库存单位编码 `stock_quantity` INT NOT NULL DEFAULT 0, -- 当前库存数量 `low_stock_threshold` INT NOT NULL DEFAULT 10, -- 低库存预警阈值 (低于10时预警) `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
预警日志表(可选,用于记录历史预警)
CREATE TABLE `stock_alerts` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`product_id` INT NOT NULL,
`alert_type` ENUM('low_stock', 'out_of_stock', 'overstock') NOT NULL,
`current_quantity` INT NOT NULL,
`threshold` INT NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`is_notified` BOOLEAN DEFAULT FALSE, -- 标记是否已通知
FOREIGN KEY (`product_id`) REFERENCES `products`(`id`)
);
核心逻辑实现(PHP代码示例)
以下代码演示了在出库时检查并触发预警。
<?php
// 假设使用PDO连接数据库,$pdo 已初始化
/**
* 处理订单出库
* @param int $productId 产品ID
* @param int $quantity 出库数量
* @return array 结果
*/
function processOrderOutbound($productId, $quantity) {
global $pdo; // 实际项目中请使用依赖注入
try {
$pdo->beginTransaction();
// 1. 查询当前库存和预警阈值(加锁防止并发)
$sql = "SELECT id, stock_quantity, low_stock_threshold
FROM products
WHERE id = ? FOR UPDATE";
$stmt = $pdo->prepare($sql);
$stmt->execute([$productId]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$product) {
throw new Exception('产品不存在');
}
$newQuantity = $product['stock_quantity'] - $quantity;
// 2. 检查库存是否充足
if ($newQuantity < 0) {
throw new Exception('库存不足,无法出库');
}
// 3. 更新库存
$updateSql = "UPDATE products SET stock_quantity = ? WHERE id = ?";
$updateStmt = $pdo->prepare($updateSql);
$updateStmt->execute([$newQuantity, $productId]);
// 4. 触发库存预警检查
$alertResult = checkInventoryAndSendAlert($productId, $newQuantity, $product['low_stock_threshold']);
$pdo->commit();
return [
'success' => true,
'new_quantity' => $newQuantity,
'alert' => $alertResult
];
} catch (Exception $e) {
$pdo->rollBack();
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* 检查库存并发送预警
* @param int $productId
* @param int $currentQuantity
* @param int $threshold
* @return array
*/
function checkInventoryAndSendAlert($productId, $currentQuantity, $threshold) {
global $pdo;
$alertType = null;
$message = '';
if ($currentQuantity <= 0) {
$alertType = 'out_of_stock';
$message = "产品 ID:{$productId} 已缺货!";
} elseif ($currentQuantity <= $threshold) {
$alertType = 'low_stock';
$message = "产品 ID:{$productId} 库存紧张!当前库存: {$currentQuantity}, 预警阈值: {$threshold}";
}
if ($alertType) {
// 5. 记录预警日志(防止重复通知)
$logSql = "INSERT INTO stock_alerts (product_id, alert_type, current_quantity, threshold)
VALUES (?, ?, ?, ?)";
$logStmt = $pdo->prepare($logSql);
$logStmt->execute([$productId, $alertType, $currentQuantity, $threshold]);
// 6. 发送通知(邮件/短信/站内信)
sendAlertNotification($productId, $alertType, $message);
return ['alert_sent' => true, 'type' => $alertType, 'message' => $message];
}
return ['alert_sent' => false];
}
/**
* 发送预警通知(示例:保存到站内信表)
*/
function sendAlertNotification($productId, $alertType, $message) {
// 实际项目中,这里可以调用邮件API (如 Mailgun/SendGrid)
// 或短信API (如阿里云/腾讯云短信)
// 或写入站内信表
// file_put_contents('/tmp/stock_alert.log', date('Y-m-d H:i:s') . " - " . $message . PHP_EOL, FILE_APPEND);
// 示例:写入站内信表
// $insertSql = "INSERT INTO user_notifications (user_id, title, content) VALUES (?, ?, ?)";
// ...
}
预警触发与通知方式
-
同步触发(如上例):
- 缺点:通知过程(特别是发邮件/短信)会拖慢用户请求,如果通知API超时,会导致下单失败。
- 改进:将通知任务放入消息队列(如 Redis 的 List 或 RabbitMQ),由后台 Worker 异步处理。
-
异步任务方式:
// 当检测到预警时,不直接发送,而是将任务推入队列 $redis->lpush('stock_alert_queue', json_encode([ 'product_id' => $productId, 'alert_type' => 'low_stock', 'message' => $message ])); // 返回结果给用户,另一个进程(Woker)读取队列并发送邮件 -
定时任务(Cron Job):
- 适合离线检查或批量检查。
crontab -e:* * * * * /usr/bin/php /path/to/check_stock_alerts.php- 定时脚本代码:
// check_stock_alerts.php $sql = "SELECT id, name, stock_quantity, low_stock_threshold FROM products WHERE stock_quantity <= low_stock_threshold"; $products = $pdo->query($sql)->fetchAll();
foreach ($products as $product) { // 检查是否已在最近N分钟内发送过相同预警,避免重复 // 发送通知... }
最佳实践与注意事项
- 避免重复预警:
- 在
stock_alerts表中记录上次预警时间,同一产品同一类型的预警在短时间内(如1小时)不重复通知,可以使用created_at字段进行判断。
- 在
- 并发安全:
- 库存操作必须使用数据库事务和行锁(
FOR UPDATE),避免高并发下出现超卖或库存负数。
- 库存操作必须使用数据库事务和行锁(
- 不同产品不同阈值:
- 不是所有商品都用同一个阈值(昂贵配件阈值可设1,快消品阈值可设100),在
products表中为每个产品单独设置low_stock_threshold字段。
- 不是所有商品都用同一个阈值(昂贵配件阈值可设1,快消品阈值可设100),在
- 区分预警等级:
- 缺货(
out_of_stock)、低库存(low_stock)、高库存(overstock,避免资金积压),不同等级使用不同通知强度(如:低库存发邮件,缺货发短信)。
- 缺货(
- 使用消息队列:
对于中大型项目,强烈建议将通知操作异步化,使用 Redis、RabbitMQ 或 Beanstalkd 来处理,提升 API 响应速度。
- 监控与看板:
- 除了主动通知,建议在管理后台提供一个库存预警看板,用颜色(红色=缺货,黄色=低库存)直观展示所有异常商品。
| 方案 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|
| 同步检查 | 小型项目,低并发 | 实现简单,实时性高 | 可能延迟用户请求 |
| 异步队列 | 中大型项目,高并发 | 响应快,解耦,稳定 | 需要维护队列组件 (Redis/RabbitMQ) |
| 定时任务 | 批量、非实时检查 | 实现简单,适合离线数据 | 实时性差,可能错过高峰预警 |
推荐的实现路径: 先用同步检查 + 定时任务快速实现(适合大多数中小企业),当业务量增长后再将通知部分改为消息队列异步。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播