oracle触发器与主dml共享同一事务上下文,非自治事务中禁止commit/rollback,否则报ora-04092;唯一合法绕过方式是pragma autonomous_transaction,它创建完全隔离的新事务,须显式提交或回滚,适用于审计日志等需独立持久化的场景。

触发器和主DML共享同一个事务上下文
Oracle 触发器不是独立事务单元,它运行在触发它的 INSERT、UPDATE 或 DELETE 语句所开启的事务中。所有操作——包括触发器里写的 INSERT INTO audit_log——都共用同一份 undo log、同一事务 ID 和隔离快照。你不能在函数里擅自结束调用它的进程,同理也不能在触发器里“中途切段”事务。
显式 COMMIT/ROLLBACK 会直接报 ORA-04092
只要触发器主体或它调用的任意存储过程/函数里出现 COMMIT、ROLLBACK、SAVEPOINT,或者隐式提交的 DDL(如 TRUNCATE TABLE、CREATE INDEX),Oracle 就会立刻抛出 ORA-04092: cannot commit in a trigger。
- 哪怕只是间接调用:触发器 →
proc_log_error→ 里面写了COMMIT,照样报错 -
EXECUTE IMMEDIATE 'TRUNCATE t'也无效,因为 DDL 隐式提交 - DDL 类型的系统触发器(如
BEFORE DROP ON DATABASE)允许 DDL,但依然禁止COMMIT
自治事务(PRAGMA AUTONOMOUS_TRANSACTION)是唯一合法绕过方式
它不是“子事务”,而是真正隔离的新事务:启动时新建事务 ID、独立 undo log、不继承主事务的隔离级别。只适用于结果必须持久化、且不能被主事务成败影响的场景:
- 审计日志写入(主事务回滚,日志仍保留)
- 错误跟踪表插入(比如记录某次失败的更新)
- 插入待发送消息队列(不依赖主事务成功)
使用时必须注意:
-
PRAGMA AUTONOMOUS_TRANSACTION必须放在DECLARE块第一行 - 自治事务内所有 DML 后必须显式
COMMIT或ROLLBACK,否则退出时报ORA-06519 - 不能用它去更新业务主表字段,否则数据状态与主事务不一致,极易引发逻辑错乱
非 DML 操作根本不在事务控制范围内
你在触发器里调用 UTL_FILE.PUT_LINE 写文件、执行 DBMS_SCHEDULER.CREATE_JOB、甚至发 HTTP 请求,这些动作都不进 Oracle 事务调度器视野。它们执行即生效,ROLLBACK 对其完全无效。
更隐蔽的是:SELECT FOR UPDATE 或 LOCK TABLES 这类语句,在某些版本或隔离级别下可能触发隐式提交,导致前面所有变更提前落盘。事务是否真正在跑,得靠 SELECT * FROM V$TRANSACTION 或 DBMS_TRANSACTION.LOCAL_TRANSACTION_ID 实锤,不能凭感觉判断。











