不能。SQL触发器本身不支持直接发送报警信号,无法调用邮件、Webhook等外部服务,仅能写入告警表或通过NOTIFY通知同实例进程,真报警必须依赖外部程序消费队列或监听事件。

SQL触发器能直接发报警信号吗
不能。CREATE TRIGGER 本身不支持调用外部通知服务(如邮件、Webhook、消息队列),也不提供 SIGNAL 语句向应用层抛出自定义中断(MySQL 5.5+ 的 SIGNAL 仅用于存储过程内错误抛出,无法穿透到客户端或触发外部动作)。
常见误解是以为在触发器里写个 SELECT 'ALERT!' 或 INSERT INTO log_table 就算“报警”——这其实只是记录,不是报警。真报警必须走出数据库边界。
MySQL中用触发器+表轮询模拟报警的实操方式
适用场景:无法改应用代码、无中间件、仅靠纯 SQL 维护的遗留系统。
- 在业务表(如
sensor_data)上建 BEFORE INSERT 触发器
- 当新插入值超过阈值(如
temperature > 100),写入专用报警表 alert_queue(含 id、table_name、record_id、alert_type、created_at)
- 外部脚本(如 Python/Shell)每 5–30 秒查一次
alert_queue,有新记录就调用 curl 发企业微信/钉钉/邮件,然后 DELETE 已处理记录
sensor_data)上建 BEFORE INSERT 触发器 temperature > 100),写入专用报警表 alert_queue(含 id、table_name、record_id、alert_type、created_at) alert_queue,有新记录就调用 curl 发企业微信/钉钉/邮件,然后 DELETE 已处理记录 注意点:
- 触发器里禁止执行耗时操作(如远程 HTTP 请求),否则会阻塞事务、拖垮写入性能
-
alert_queue表引擎建议用InnoDB,加INDEX(created_at)加速轮询查询 - 轮询脚本需加分布式锁(如用
GET_LOCK())避免多实例重复消费
PostgreSQL中用LISTEN/NOTIFY做轻量实时通知
比轮询更高效,但只限同一数据库实例内的进程通信:
- 在触发器中执行
PERFORM pg_notify('alert_channel', json_build_object(...)::text)
- 应用或监听进程用
LISTEN alert_channel 持久连接接收事件
- 收到通知后,由该进程负责调用外部 API 或发邮件
PERFORM pg_notify('alert_channel', json_build_object(...)::text) LISTEN alert_channel 持久连接接收事件 优势:
- 零延迟(毫秒级)
- 不需要轮询、无空查开销
- PostgreSQL 原生支持,无需额外表
限制:
-
NOTIFY不保证送达(连接断开即丢失),不适合关键告警 - 不能跨数据库实例;监听端必须保持长连接,运维成本略高
真正可靠的报警必须跳出SQL逻辑
触发器只是数据变更的“钩子”,不是报警执行单元。生产环境推荐路径是:
- 业务应用层写库前校验阈值,命中即同步发告警(响应快、可控性强)
- 或用 CDC 工具(如 Debezium、Canal)捕获 binlog / WAL,解析后投递到 Kafka,再由告警服务消费
- 若只能动数据库,MySQL 用触发器写队列表 + 外部轮询,PostgreSQL 优先选 NOTIFY,但都得配超时重试、去重、状态跟踪
容易被忽略的是告警抑制和收敛——同一异常连续写入 100 条,不该发 100 条消息。这个逻辑几乎不可能在触发器里合理实现。










