触发器仅适用于细粒度dml审计缺口,如需记录salary字段变更详情且fga不支持新旧值时才使用;必须用after row触发器配合:old/:new引用、autonomous_transaction,并避免mutating table错误及ddl误用。

触发器不是万能的审计工具,它只适合补细粒度 DML 变更审计的缺口——比如你必须知道 SALARY 字段被谁、从多少改成了多少,而 DBMS_FGA 又不支持记录旧值/新值时,才轮到触发器上场。
用 AFTER ROW 触发器捕获字段变更细节
要拿到变更前后的值,必须用 AFTER UPDATE FOR EACH ROW,且显式引用 :OLD.salary 和 :NEW.salary。BEFORE 触发器拿不到 :NEW 的完整状态,AFTER STATEMENT 则根本看不到行级数据。
- 必须加
PRAGMA AUTONOMOUS_TRANSACTION:否则审计日志插入会和主事务绑死,一回滚就全丢 - 别在触发器里直接写
INSERT INTO audit_log VALUES (:OLD.salary, :NEW.salary)—— 如果审计表没建好或字段类型不匹配,整个 DML 就失败 - 建议先做空值判断:
IF :OLD.salary != :NEW.salary THEN ...,避免无意义日志刷屏
绕开 ORA-04091 mutating table 错误
常见错误是想偷懒用 TO_CLOB(:OLD) 或 JSON_OBJECT(*) 一键序列化整行,结果触发 ORA-04091: table is mutating。Oracle 不允许在行级触发器里查当前正被修改的表。
- 只提取真正关心的字段,比如
JSON_OBJECT('salary' VALUE :OLD.salary, 'emp_id' VALUE :OLD.emp_id) - 绝对不要出现
SELECT ... FROM employees WHERE emp_id = :OLD.emp_id这类查询 - 如果真需要关联其他表(如查操作人姓名),确保目标表与触发器所在表无 DML 依赖链
DDL 操作审计必须用系统级触发器
想抓 CREATE TABLE、DROP INDEX 这类动作,不能靠普通表触发器——它们只响应 DML。得用 AFTER CREATE ON DATABASE 或 AFTER CREATE ON SCHEMA 级别的系统触发器。
-
ORA_DICT_OBJ_NAME、ORA_DICT_OBJ_TYPE、ORA_LOGIN_USER是关键上下文变量 - DDL 触发器里不能用
COMMIT或ROLLBACK,但可以带PRAGMA AUTONOMOUS_TRANSACTION写审计日志 - 注意权限:创建数据库级 DDL 触发器需
ADMINISTER DATABASE TRIGGER权限,不是普通 DBA 角色默认拥有
别把触发器当 FGA 替代品
如果你只是想“记录谁查了 EMPLOYEES 表”,直接用 DBMS_FGA.ADD_POLICY 更稳——它不侵入业务逻辑、不拖慢 DML、还能审计 SELECT。触发器只该出现在 FGA 做不到的地方:比如要存 :OLD/:NEW、要调用外部 HTTP 接口告警、或老版本 Oracle(8i/9i)没 FGA 可用。
最常被忽略的一点:触发器本身没有开关机制,禁用得靠 ALTER TRIGGER xxx DISABLE,而生产环境里一旦漏掉这步,后续改表结构可能被触发器意外阻断。











