创建UPDATE触发器更新同表字段时,是否会重复触发该触发器?
关于UPDATE触发器修改同表字段是否会递归触发的问题
这个问题问得太实用了——毕竟一不小心就可能踩进无限递归的坑!答案其实得看你使用的数据库系统,不同数据库的默认规则和处理逻辑差异不小:
MySQL 场景
MySQL 默认是禁止同表触发器递归触发的。也就是说,当你的触发器里对同一张表执行UPDATE操作时,不会再次触发同一个触发器。
举个例子,你写的这个需求:
CREATE TRIGGER trg_item_update_cost AFTER UPDATE ON Item FOR EACH ROW BEGIN -- 即使不加判断,MySQL也不会递归触发这个触发器 UPDATE Item SET cost = 99 WHERE id = NEW.id; END;
不过还是建议加个判断条件,避免无意义的更新操作:
CREATE TRIGGER trg_item_update_cost AFTER UPDATE ON Item FOR EACH ROW BEGIN IF NEW.cost != 99 THEN UPDATE Item SET cost = 99 WHERE id = NEW.id; END IF; END;
SQL Server 场景
SQL Server 的规则相对灵活,默认情况下直接递归触发是被禁止的(通过 RECURSIVE_TRIGGERS 数据库选项控制,默认值为 OFF),但间接递归(比如触发器A触发触发器B,再触发触发器A)是否允许取决于 Nested Triggers 选项(默认开启)。
如果你的场景是触发器自己更新同表字段,默认不会递归触发;但如果手动开启了 RECURSIVE_TRIGGERS,就会触发直到达到默认32层的递归限制,甚至报错。所以同样建议在触发器里加条件判断,或者保持默认的递归禁用设置。
PostgreSQL 场景
PostgreSQL 默认允许递归触发,而且有默认100层的递归深度限制。如果你的触发器里没有加判断,直接更新同表字段,会陷入反复触发的循环,直到超过深度限制抛出错误。
这里更推荐用 BEFORE UPDATE 触发器直接修改字段值,而不是用 AFTER UPDATE 再去执行UPDATE语句——这样既高效,又能从根源避免递归问题:
CREATE OR REPLACE FUNCTION set_cost_to_99() RETURNS TRIGGER AS $$ BEGIN IF NEW.cost != 99 THEN NEW.cost := 99; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_item_update_cost BEFORE UPDATE OF cost ON Item FOR EACH ROW EXECUTE FUNCTION set_cost_to_99();
总结建议
- 不同数据库的默认行为差异很大,一定要结合你使用的数据库文档确认规则
- 无论用哪种数据库,在触发器里加条件判断都是好习惯——只在需要修改的时候执行操作,避免无意义的触发和性能损耗
- 优先考虑用
BEFORE触发器直接修改字段值,而非AFTER触发器再执行表更新,能有效规避递归风险
内容的提问来源于stack exchange,提问作者Liam neesan
相关产品推荐
相关产品推荐

