SQL触发器不能直接发邮件,因事务上下文中禁止阻塞式网络调用;主流方案均为异步解耦:MySQL用触发器写预警表+事件轮询、SQL Server用AlertQueue+SQL Agent、PostgreSQL用NOTIFY+外部监听器。

SQL触发器本身不能直接发邮件——所有主流数据库(MySQL、PostgreSQL、SQL Server)的触发器都运行在事务上下文中,不支持阻塞式网络调用(如SMTP),强行集成邮件逻辑会导致事务超时、锁表甚至崩溃。
MySQL 中触发器 + 事件轮询实现准实时预警
MySQL 触发器无法调用 SEND_EMAIL() 或执行系统命令,但可以写入一张预警队列表,再由外部脚本或数据库事件定期扫描处理。
- 先建预警记录表:
CREATE TABLE inventory_alert_log (id BIGINT AUTO_INCREMENT PRIMARY KEY, product_id INT, stock INT, threshold INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP); - 在库存更新触发器中插入预警:
INSERT INTO inventory_alert_log (product_id, stock, threshold) VALUES (NEW.id, NEW.stock, 10);(假设阈值为10) - 用
EVENT每30秒查一次:SELECT * FROM inventory_alert_log WHERE processed = 0;,然后调用外部 Python 脚本发送邮件并标记processed = 1 - 注意:MySQL 事件默认关闭,需确认
event_scheduler = ON;且触发器内不能用SELECT或事务控制语句
SQL Server 的 CLR 触发器(高风险慎用)
SQL Server 允许通过启用 CLR 集成,在触发器里调用 .NET 代码发邮件,但生产环境强烈不推荐:
- 必须将数据库设为
TRUSTWORTHY ON或使用证书签名,大幅降低安全性 - 邮件发送是同步阻塞操作,若 SMTP 延迟或失败,会拖垮整个
UPDATE事务 - SQL Server 2017+ 默认禁用
sp_OACreate等旧接口,CLR 需手动部署、签名、权限授权,运维成本极高 - 更稳妥的做法仍是写入
AlertQueue表,由 SQL Agent Job 定期拉取并调用msdb.dbo.sp_send_dbmail
PostgreSQL 使用 LISTEN/NOTIFY + 外部监听器
PostgreSQL 触发器可安全触发 NOTIFY,这是轻量级异步通知机制,不阻塞事务,适合解耦预警动作:
- 触发器中写:
PERFORM pg_notify('low_stock_alert', json_build_object('product_id', NEW.id, 'stock', NEW.stock)::text); - 用 Python(
psycopg2)或 Node.js(pg)长期监听low_stock_alert通道,收到消息后立即发邮件 - 优势:无轮询开销、响应快(毫秒级)、不侵入数据库事务、便于水平扩展监听服务
- 坑点:
NOTIFY不保证投递(连接断开时丢失),需搭配幂等处理和本地日志落盘
真正落地时,95% 的团队最终都会放弃“触发器直发邮件”的想法——不是不会写,而是它把可靠性、可观测性和运维边界全搅乱了。预警的核心矛盾从来不在“怎么通知”,而在于“谁来负责重试、去重、渠道降级和告警收敛”。把发邮件这件事彻底移出数据库,才是最不容易半夜被叫醒的方案。

















