如何检测触发器触发的DML操作类型(INSERT/UPDATE/DELETE)以记录操作日志?
核心疑问解答
关于序列的配置
- 完全不需要为每类DML单独创建序列。你为
LOG表ID配置的专属自增序列已经可以复用,和日志对应的DML操作类型没有耦合,单条序列就能满足所有操作类型的日志主键生成需求。
关于触发器的实现方案
你完全不需要拆分多个触发器,直接创建一个同时绑定INSERT/UPDATE/DELETE三种操作的AFTER行级触发器即可(注意必须指定为行级触发器,否则一条DML修改多行数据时只会触发一次,无法逐行记录变更)。
操作类型的判断逻辑
所有主流数据库的触发器都内置了操作判断变量,不需要额外自定义判断逻辑:
- Oracle:提供
INSERTING、UPDATING、DELETING三个布尔内置变量,直接判断即可 - PostgreSQL:提供
TG_OP内置变量,返回值直接就是'INSERT'/'UPDATE'/'DELETE'的字符串 - MySQL:同样支持
INSERTING、UPDATING、DELETING三个判断分支
原有触发器的问题修正
你原本写的SELECT record FROM TableA逻辑存在两处核心错误:
- DELETE操作触发时,被删除的行已经从
TableA中移除,全表查询根本无法获取被删的数据 - 行级触发器必须通过触发器临时变量取当前变更行的数据:
INSERT/UPDATE取NEW临时变量的行值,DELETE取OLD临时变量的行值,否则会错误地把全表数据写入日志
修正后的触发器示例(以Oracle语法为例)
CREATE OR REPLACE TRIGGER trg_tablea_dml_log AFTER INSERT OR UPDATE OR DELETE ON TableA FOR EACH ROW -- 必须指定为行级触发,否则只会在语句执行完成后触发一次 AS v_event VARCHAR2(10); v_record VARCHAR2(1000); -- 类型按你实际LOG表record字段调整 BEGIN -- 判断当前触发的操作类型 IF INSERTING THEN v_event := 'INSERT'; v_record := :NEW.record; -- 取新插入行的record值 ELSIF UPDATING THEN v_event := 'UPDATE'; v_record := :NEW.record; -- 取变更后行的record值 ELSIF DELETING THEN v_event := 'DELETE'; v_record := :OLD.record; -- 取被删除行的record值 END IF; -- 写入日志表,ID、TS字段无需手动赋值,序列和默认值会自动填充 INSERT INTO LOG (event, record) VALUES (v_event, v_record); END;
注意:不同数据库的触发器语法细节有差异,比如PostgreSQL不需要手动判断分支,直接用
TG_OP给event赋值即可;MySQL的临时变量前缀为NEW./OLD.,不需要冒号,但整体逻辑完全一致。
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

