DDL触发器必须由SYS或SYSTEM用户创建,普通用户即使拥有DBA角色或CREATE ANY TRIGGER权限也无法创建;ON DATABASE监控全实例DDL,ON SCHEMA仅监控指定schema;ORA_DICT_OBJ_SQL在19c中常为NULL,不可靠;BEFORE DDL无法回滚,仅能中止语句。

DDL触发器必须用SYSTEM或SYS用户创建,普通用户无权定义
Oracle 19c中,AFTER DDL ON SCHEMA 或 AFTER DDL ON DATABASE 这类系统事件触发器,只能由具有ADMINISTER DATABASE TRIGGER权限的用户(通常是SYS或SYSTEM)创建。普通用户即使被授予CREATE ANY TRIGGER,也无法成功创建DDL触发器——会报错ORA-01031: insufficient privileges。
实操建议:
- 用
sqlplus / as sysdba登录,确保在SYS上下文中执行 - 不要尝试用应用用户(如
C##APP_USER)去建DDL触发器,哪怕它有DBA角色也不行 - 若必须由非SYS用户管理审计逻辑,可考虑用
DBMS_LOGMNR或UNIFIED AUDITING替代,而非触发器
ON DATABASE vs ON SCHEMA:监控范围差异直接影响日志噪音
ON DATABASE捕获整个实例所有用户的DDL操作;ON SCHEMA只捕获指定schema下的DDL(比如ON HR.SCHEMA)。两者语法不同,且不能混用。
常见错误现象:
- 写成
AFTER DDL ON HR→ 报错ORA-04072: invalid trigger type,因为缺少.SCHEMA - 想监控多个schema却只建一个
ON SCHEMA触发器 → 只能覆盖单个schema,其余被忽略 - 用
ON DATABASE但没过滤ORA_LOGIN_USER→ 日志表迅速被DBA、OGG、备份工具等自动DDL刷爆
推荐做法:优先用ON SCHEMA,并在触发器体中加判断:
IF ORA_DICT_OBJ_OWNER IN ('HR', 'OE', 'PM') THEN
INSERT INTO ddl_audit_log ...
END IF;
ORA_DICT_OBJ_SQL不可靠,别指望它存完整DDL语句
很多资料提到ORA_DICT_OBJ_SQL能拿到原始DDL文本,但在Oracle 19c中,这个值多数情况下为NULL,尤其在PL/SQL块内执行DDL(如EXECUTE IMMEDIATE)、通过工具(SQL Developer、Toad)或JDBC提交时。官方文档明确说明其值“not guaranteed”。
所以依赖它做语句回放或合规审计是危险的。替代方案:
- 记录
ORA_SYSEVENT(如'CREATE')、ORA_DICT_OBJ_TYPE(如'TABLE')、ORA_DICT_OBJ_NAME(如'EMPLOYEES')这三个字段,至少能还原操作意图 - 配合
DBA_AUDIT_TRAIL或统一审计策略(UNIFIED AUDIT POLICY)补全SQL文本,但需额外开启审计 - 如果真要捕获SQL,得在应用层或中间件拦截,而非依赖触发器
BEFORE DDL触发器无法ROLLBACK,限制操作要格外小心
BEFORE DDL触发器可用于阻止特定DDL(例如禁止DROP TABLE),但要注意:它不能像DML那样回滚事务,而是直接中止当前DDL语句。一旦触发RAISE_APPLICATION_ERROR,整个语句立即失败,且不会留下任何中间状态。
容易踩的坑:
- 在
BEFORE DDL ON DATABASE中抛异常 → 所有用户(包括DBA)的DDL都会被拦,可能锁死维护窗口 - 未排除
ORA_DICT_OBJ_OWNER = 'SYS'→ 连GRANT、CREATE SYNONYM这类系统级操作也被禁,导致权限体系紊乱 - 忘记测试触发器自删除能力 → Oracle允许
DROP TRIGGER绕过自身限制,但若写错逻辑(比如误判触发条件),可能陷入“自己删不掉自己”的窘境
真正需要限制时,应限定scope(如仅ON HR.SCHEMA),并显式排除SYS和SYSTEM用户。


















