应监听articles表的status字段,仅在old.status≠new.status且new.status为'published'或'archived'时触发,避免误响应标题等无关更新;联动逻辑须解耦,触发器仅写task_queue表,由后台任务异步处理外部依赖。

触发器该监听哪个表和字段
内容管理系统中,文章发布状态通常由 status 字段控制(如 'draft'、'published'、'archived'),而联动行为往往涉及其他表:比如 article_categories(更新分类统计)、search_index(同步全文检索数据)、notifications(生成推送任务)。触发器必须建在主文章表(如 articles)上,并且只响应 status 的变更——不是所有 UPDATE 都要触发,否则编辑标题、作者时也会误触发。
实操建议:
- 用
BEFORE UPDATE或AFTER UPDATE,优先选AFTER UPDATE,避免在触发器里读取未提交的新值 - 加条件判断:仅当
OLD.status != NEW.status且新值为'published'或'archived'时才执行联动逻辑 - 不要监听
INSERT——新建文章默认是草稿,发布是显式操作,应由业务层或状态机控制
触发器里调用外部服务或写入多张表是否可行
直接在 SQL 触发器里发起 HTTP 请求(如调用搜索服务 API)几乎不可行:MySQL / PostgreSQL 原生不支持网络调用,强行用 UDF 或扩展(如 sys_exec)会严重破坏事务一致性、引入超时风险,且难以调试。
实操建议:
- 触发器只做轻量、事务安全的操作:例如更新
categories表的published_count字段,或向task_queue表插入一条记录(含article_id、action、created_at) - 把耗时/外部依赖逻辑交给后台任务系统(如 Celery、Sidekiq 或自研轮询服务)消费
task_queue - 避免在触发器中写入三张以上表——容易锁表、拖慢主流程;如果必须批量更新,先用临时表暂存 ID 列表再分批处理
PostgreSQL 和 MySQL 在触发器写法上的关键差异
两者语法接近,但关键细节极易踩坑。比如 PostgreSQL 要求触发器函数必须返回 TRIGGER 类型,而 MySQL 不强制;又比如对 NEW 和 OLD 的引用方式不同。
实操建议:
- PostgreSQL 中,触发器函数需显式定义并用
CREATE FUNCTION ... RETURNS TRIGGER,最后用RETURN NEW(BEFORE)或RETURN NULL(AFTER) - MySQL 中,触发器体直接写 SQL 语句,用
NEW.status和OLD.status,但不能在BEFORE UPDATE中给NEW.status赋值后再调用其他语句——赋值必须是触发器内最后一条语句 - 两者都不支持在触发器中使用事务控制语句(
COMMIT/ROLLBACK),出错会自动回滚整个外部事务
为什么上线后突然变慢?常见性能陷阱
触发器本身不慢,慢的是它引发的连锁反应:比如每次发布都去 UPDATE 分类统计,而该表被频繁读取;或者触发器往 search_index 插入大文本,却没建好索引,导致写放大。
实操建议:
- 在触发器涉及的关联表上,确保有覆盖查询条件的索引,例如
ON article_categories(category_id)、ON task_queue(status, created_at) - 避免在触发器中执行
SELECT ... FROM ... WHERE text_column LIKE '%xxx%'这类全表扫描 - 测试阶段用
EXPLAIN ANALYZE(PostgreSQL)或EXPLAIN FORMAT=JSON(MySQL)看触发器隐式执行的语句实际走了什么执行计划
真正难的不是写触发器,而是判断「这个联动逻辑到底该不该放在这里」——状态变更只是信号,后续动作是否需要强一致性、是否允许延迟、失败后如何补偿,这些决定了触发器只是起点,而不是终点。











