自治事务是独立提交的事务,pragma autonomous_transaction必须紧贴is/as放在声明区首行,且自治过程内必须有且仅有一次commit或rollback,否则抛ora-06519;它与主事务完全隔离,序列递增不可逆,也无法读取主事务未提交数据。

自治事务不是“自动提交”,而是“独立提交”——日志写不进表,八成是 PRAGMA AUTONOMOUS_TRANSACTION 放错了位置,或漏了 COMMIT。
PRAGMA AUTONOMOUS_TRANSACTION 必须紧挨 IS/AS 放在最开头
它不是普通语句,是编译期指令,放错地方直接报 PLS-00103。常见错误包括:塞在 BEGIN 后面、包规范(spec)里、IF 分支中、甚至 SQL*Plus 的匿名块里。
- ✅ 正确位置:
CREATE OR REPLACE PROCEDURE p_log(...) IS PRAGMA AUTONOMOUS_TRANSACTION;—— 紧贴IS后,声明区第一行 - ❌ 错误位置:
BEGIN PRAGMA AUTONOMOUS_TRANSACTION;或DECLARE PRAGMA ... BEGIN - ❌ 触发器里也一样:必须在
DECLARE块的最顶部,不能在BEGIN之后 - ❌ 匿名块不支持:SQL*Plus 中的
BEGIN ... END;加这句会报PLS-00702
自治过程里必须有且仅有一次 COMMIT 或 ROLLBACK
自治事务一旦启动,就和主事务彻底脱钩,Oracle 不会帮你兜底。没显式结束,退出时必抛 ORA-06519,且自动回滚整个自治块——你插的日志就白写了。
- 正常路径末尾加
COMMIT,别省 - 异常分支里必须加
ROLLBACK,不能只RAISE;否则异常一出,自治事务悬空 - 嵌套调用另一个自治过程?那它也得自己管好自己的
COMMIT/ROLLBACK,不能指望外层收尾 - 示例关键片段:
CREATE OR REPLACE PROCEDURE p_log_error(p_msg VARCHAR2) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO t_log(msg, ts) VALUES (p_msg, SYSDATE);
COMMIT; -- ← 必须有
EXCEPTION
WHEN OTHERS THEN
ROLLBACK; -- ← 出错也要收尾
RAISE;
END;
主事务异常时,只调用自治过程,不碰事务语句
很多人在主过程的 EXCEPTION 块里写 INSERT INTO t_log ...; COMMIT;,以为能保住日志——但这条 INSERT 仍属于主事务,主事务一 ROLLBACK,它跟着丢。
- 真正有效的做法:把日志逻辑完全剥离,封装成自治过程,主过程里只做一次调用
- 主过程里禁止在
EXCEPTION中执行任何 DML +COMMIT组合 - 自治过程插入的数据,主事务无论
COMMIT还是ROLLBACK,它都已落地 - 注意:自治事务查不到主事务未提交的数据,但主事务能立刻看到它已
COMMIT的日志行
序列值推进不可逆,且自治事务看不到主事务中间态
这是容易被忽略的副作用:自治事务调用 SEQ.NEXTVAL,序列真实递增,哪怕主事务最终回滚,这个值也不会回收。
- 如果业务依赖连续或可预测的序列号(比如单据编号),需评估是否接受跳号
- 自治过程内查询主事务刚
INSERT但未COMMIT的数据,会查不到——这不是 bug,是隔离性保障 - 别在自治过程里写需要读取主事务中间状态的校验逻辑,它天然看不到
- 审计日志、错误跟踪、状态快照这类“只写不管上下文”的场景,才真正适合自治事务











