You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Express.js中实现MySQL库存字段为5时自动发预警邮件

Express.js 实现库存阈值自动发邮件方案

核心逻辑分两种实现路径,实时性要求高选库存更新后即时检查,没有统一库存操作入口就选定时轮询,下面是可直接落地的代码:

前置依赖安装

先装需要的第三方包,执行命令:

npm install express mysql2 nodemailer node-cron dotenv
  • mysql2:连接MySQL数据库的驱动,比老版mysql包性能好、支持Promise
  • nodemailer:Node.js生态最常用的发邮件库,兼容绝大多数SMTP服务
  • node-cron:实现定时任务,轮询方案用
  • dotenv:加载环境变量,避免敏感配置硬编码

第一步:基础配置

首先在项目根目录建.env文件存配置,别把敏感信息写在业务代码里:

# 数据库配置
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=你的数据库账号
DB_PASSWORD=你的数据库密码
DB_NAME=你的库名

# 邮件SMTP配置 用自己企业邮箱/QQ邮箱/163邮箱的SMTP信息就行
SMTP_HOST=smtp.你的邮箱服务商.com
SMTP_PORT=465
SMTP_SECURE=true
SMTP_USER=你的发件邮箱地址
SMTP_PASS=你的邮箱SMTP授权码
NOTIFY_RECEIVER=要接收预警的收件人邮箱

注意:先给product表加个tinyint类型的is_low_stock_notified字段,默认值0,用来标记是否已经发过该商品的低库存预警,避免重复发邮件骚扰。库存补货回到5以上的时候,把这个字段重置为0即可。

第二步:初始化服务连接

新建app.js,先初始化数据库连接池、邮件发送实例:

require('dotenv').config();
const express = require('express');
const mysql = require('mysql2/promise');
const nodemailer = require('nodemailer');
const cron = require('node-cron');

const app = express();
app.use(express.json());

// 初始化数据库连接池
const db = mysql.createPool({
  host: process.env.DB_HOST,
  port: process.env.DB_PORT,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  waitForConnections: true,
  connectionLimit: 10
});

// 初始化邮件发送器
const mailTransporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: process.env.SMTP_PORT,
  secure: process.env.SMTP_SECURE,
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS
  }
});

// 封装低库存预警邮件发送函数
async function sendLowStockAlert(product) {
  const mailOptions = {
    from: process.env.SMTP_USER,
    to: process.env.NOTIFY_RECEIVER,
    subject: `【库存预警】商品ID ${product['Product ID']} 库存不足`,
    html: `
      <p>检测到以下商品库存已达到预警阈值(5件):</p>
      <ul>
        <li>商品ID:${product['Product ID']}</li>
        <li>商品描述:${product.ProductDescription}</li>
        <li>当前库存:${product.ProductQuantity} 件</li>
      </ul>
      <p>请及时补货。</p>
    `
  };

  try {
    await mailTransporter.sendMail(mailOptions);
    // 发完邮件更新标记位,避免重复发送
    await db.query(
      'UPDATE product SET is_low_stock_notified = 1 WHERE `Product ID` = ?',
      [product['Product ID']]
    );
    console.log(`商品${product['Product ID']}低库存预警邮件已发送`);
  } catch (err) {
    console.error(`邮件发送失败,商品ID${product['Product ID']}:`, err);
  }
}

第三步:选择触发逻辑

方案1:即时触发(推荐,无延迟)

所有涉及修改商品库存的接口(比如出库、库存调整接口),在库存更新完成后立刻检查库存值,符合阈值就发邮件:

// 库存更新接口示例
app.put('/api/product/:id/stock', async (req, res) => {
  const productId = req.params.id;
  const { newQuantity } = req.body;

  try {
    // 更新库存
    await db.query(
      'UPDATE product SET ProductQuantity = ? WHERE `Product ID` = ?',
      [newQuantity, productId]
    );

    // 如果库存更新后大于5,重置通知标记,方便下次降到5时再发通知
    if (newQuantity > 5) {
      await db.query(
        'UPDATE product SET is_low_stock_notified = 0 WHERE `Product ID` = ?',
        [productId]
      );
    }

    // 库存等于5且没发过通知,触发邮件
    if (newQuantity === 5) {
      const [products] = await db.query(
        'SELECT * FROM product WHERE `Product ID` = ? AND is_low_stock_notified = 0',
        [productId]
      );
      if (products.length > 0) {
        // 不用await等邮件发完,异步发不阻塞接口响应
        sendLowStockAlert(products[0]);
      }
    }

    res.send({ code: 0, msg: '库存更新成功' });
  } catch (err) {
    res.status(500).send({ code: 500, msg: '库存更新失败', err: err.message });
  }
});

方案2:定时轮询(适合无统一库存入口的场景)

如果你的库存修改逻辑散落在多个地方,不好统一加检查逻辑,就用定时任务定期扫库,比如每小时整点查一次符合阈值的商品发通知:

// 定时任务:cron表达式'0 * * * *'代表每小时0分执行,可根据需要调整频率
cron.schedule('0 * * * *', async () => {
  console.log('开始执行低库存检查任务');
  try {
    // 查所有库存<=5且未发过通知的商品
    const [needAlertProducts] = await db.query(
      'SELECT * FROM product WHERE ProductQuantity <= 5 AND is_low_stock_notified = 0'
    );

    // 遍历发邮件
    for (const product of needAlertProducts) {
      await sendLowStockAlert(product);
    }
    console.log(`低库存检查完成,共发送${needAlertProducts.length}封预警邮件`);
  } catch (err) {
    console.error('低库存检查任务执行失败:', err);
  }
});

// 启动服务
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`服务运行在http://localhost:${PORT}`);
});

注意事项

  • 邮件发送逻辑不要加await阻塞主业务流程,异步执行即可,避免因为邮件服务故障导致库存接口响应超时
  • 如果要给不同商品对应不同的负责人发邮件,只需要在product表加个notify_email字段存对应负责人的邮箱,发邮件的时候取这个字段当收件人就行
  • 定时任务频率别设太高,比如几秒跑一次会给数据库造成不必要的压力,一般10分钟到1小时一次足够
  • 生产环境建议给邮件发送加失败重试机制,避免因为网络波动导致漏发

内容的提问来源于stack exchange,提问作者Ayan Ahmed Rabbi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 11:15:42