如何在Express.js中实现MySQL库存字段为5时自动发预警邮件
Express.js 实现库存阈值自动发邮件方案
核心逻辑分两种实现路径,实时性要求高选库存更新后即时检查,没有统一库存操作入口就选定时轮询,下面是可直接落地的代码:
前置依赖安装
先装需要的第三方包,执行命令:
npm install express mysql2 nodemailer node-cron dotenv
mysql2:连接MySQL数据库的驱动,比老版mysql包性能好、支持Promisenodemailer: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
相关产品推荐
相关产品推荐

