PHP项目如何实现库存预警?

wen java案例 3

本文目录导读:

PHP项目如何实现库存预警?

  1. 数据库表设计
  2. 核心逻辑实现(PHP代码示例)
  3. 预警触发与通知方式
  4. 最佳实践与注意事项

在PHP项目中实现库存预警,核心思路是在业务逻辑的关键节点(如下单、入库、出库)检查库存数量,并与设定的预警阈值进行比较,当低于阈值时触发通知

下面我将从数据表设计核心逻辑实现预警方式最佳实践四个方面,为你提供一个完整的实现方案。

数据库表设计

你需要一个基础的库存表和预警规则表。

产品库存表 (productsinventory)

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 (?, ?, ?)";
    // ...
}

预警触发与通知方式

  1. 同步触发(如上例)

    • 缺点:通知过程(特别是发邮件/短信)会拖慢用户请求,如果通知API超时,会导致下单失败。
    • 改进:将通知任务放入消息队列(如 Redis 的 List 或 RabbitMQ),由后台 Worker 异步处理。
  2. 异步任务方式

    // 当检测到预警时,不直接发送,而是将任务推入队列
    $redis->lpush('stock_alert_queue', json_encode([
        'product_id' => $productId,
        'alert_type' => 'low_stock',
        'message' => $message
    ]));
    // 返回结果给用户,另一个进程(Woker)读取队列并发送邮件
  3. 定时任务(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分钟内发送过相同预警,避免重复 // 发送通知... }

最佳实践与注意事项

  1. 避免重复预警
    • stock_alerts 表中记录上次预警时间,同一产品同一类型的预警在短时间内(如1小时)不重复通知,可以使用 created_at 字段进行判断。
  2. 并发安全
    • 库存操作必须使用数据库事务行锁(FOR UPDATE,避免高并发下出现超卖或库存负数。
  3. 不同产品不同阈值
    • 不是所有商品都用同一个阈值(昂贵配件阈值可设1,快消品阈值可设100),在 products 表中为每个产品单独设置 low_stock_threshold 字段。
  4. 区分预警等级
    • 缺货(out_of_stock)、低库存(low_stock)、高库存(overstock,避免资金积压),不同等级使用不同通知强度(如:低库存发邮件,缺货发短信)。
  5. 使用消息队列

    对于中大型项目,强烈建议将通知操作异步化,使用 Redis、RabbitMQ 或 Beanstalkd 来处理,提升 API 响应速度。

  6. 监控与看板
    • 除了主动通知,建议在管理后台提供一个库存预警看板,用颜色(红色=缺货,黄色=低库存)直观展示所有异常商品。
方案 适合场景 优点 缺点
同步检查 小型项目,低并发 实现简单,实时性高 可能延迟用户请求
异步队列 中大型项目,高并发 响应快,解耦,稳定 需要维护队列组件 (Redis/RabbitMQ)
定时任务 批量、非实时检查 实现简单,适合离线数据 实时性差,可能错过高峰预警

推荐的实现路径: 先用同步检查 + 定时任务快速实现(适合大多数中小企业),当业务量增长后再将通知部分改为消息队列异步

抱歉,评论功能暂时关闭!