自治事务是独立提交而非自动提交,PRAGMA必须紧贴IS/AS放在声明区首行,且自治过程内必须显式COMMIT或ROLLBACK,否则抛ORA-06519;日志需封装为自治过程调用才能脱离主事务影响。

自治事务不是“自动提交”,而是“独立提交”——日志写不进表,八成是 PRAGMA AUTONOMOUS_TRANSACTION 放错了位置,或漏了 COMMIT。
PRAGMA AUTONOMOUS_TRANSACTION 必须紧贴 IS/AS 放在声明区第一行
它不是普通语句,是编译期指令,放错地方直接报 PLS-00103。常见错误包括:
- 塞在
BEGIN后面、IF分支里、甚至 SQL*Plus 的匿名块里 - 写在包规范(spec)中,而不是包体(body)的过程内
- 触发器里放在
BEGIN之后,而不是DECLARE块顶部
✅ 正确写法:
CREATE OR REPLACE PROCEDURE p_log_error(p_msg VARCHAR2) IS PRAGMA AUTONOMOUS_TRANSACTION; -- 紧贴 IS 后,无空行,无其他语句 BEGIN INSERT INTO t_log(msg, ts) VALUES (p_msg, SYSDATE); COMMIT; END;
自治过程里必须有且仅有一次 COMMIT 或 ROLLBACK
自治事务一旦启动,就和主事务彻底脱钩,Oracle 不会帮你兜底。没显式结束,退出时必抛 ORA-06519,且自动回滚整个自治块——你插的日志就白写了。
- 正常路径末尾加
COMMIT,别省 - 异常分支里必须加
ROLLBACK,不能只RAISE;否则异常一出,自治事务悬空 - 嵌套调用另一个自治过程?那它也得自己管好自己的
COMMIT/ROLLBACK,不能指望外层收尾
主事务异常时只调用自治过程,不碰任何 DML + COMMIT 组合
很多人在主过程的 EXCEPTION 块里写 INSERT INTO t_log; COMMIT;,以为能保住日志——但这条 INSERT 仍属于主事务,主事务一 ROLLBACK,它跟着丢。
- 真正有效的做法:把日志逻辑完全剥离,封装成自治过程,主过程里只做一次调用
- 自治过程插入的数据,主事务无论
COMMIT还是ROLLBACK,它都已落地 - 注意:
DBMS_UTILITY.format_error_backtrace比$$PLSQL_LINE更准,能定位到嵌套调用中的真实出错行
自治事务的隔离性与副作用要提前意识到
它不是万能日志开关,几个关键限制常被忽略:
- 自治事务查不到主事务未提交的数据,但主事务能立刻看到它已
COMMIT的日志行 - 序列值推进不可逆——
SEQ_LOG.NEXTVAL在自治块里调用后,即使主事务回滚,序号也不会倒退 - 不能在匿名块或
DECLARE块里声明;只支持存储过程、函数、包体、触发器 - 嵌套自治事务不被允许,重复声明会报
PLS-00703
最易踩的坑,往往不在语法,而在误以为“自治 = 自动”。它只是独立,不是免维护——每个自治块都得自己扛起事务收口的责任。

















