PRAGMA AUTONOMOUS_TRANSACTION 必须紧贴IS/AS放在声明区首行,且自治过程内必须有且仅有一次COMMIT或ROLLBACK;日志需封装为自治过程并传入业务标识,用DBMS_UTILITY.format_error_backtrace定位错误。

PRAGMA AUTONOMOUS_TRANSACTION 必须紧贴 IS/AS 放在声明区第一行
自治事务不是运行时开关,而是编译期指令。放错位置直接报 PLS-00103,根本不会进入执行阶段。
- ✅ 正确:在
CREATE OR REPLACE PROCEDURE p_log(...) IS后立刻写PRAGMA AUTONOMOUS_TRANSACTION; - ❌ 错误:塞在
BEGIN之后、IF分支里、包规范(spec)中,或 SQL*Plus 匿名块里(会报PLS-00702) - 触发器中也一样:必须放在
DECLARE块最顶部,不能在BEGIN之后
自治过程里必须有且仅有一次 COMMIT 或 ROLLBACK
自治事务启动后就和主事务完全脱钩,Oracle 不会帮你兜底。没显式结束,退出必抛 ORA-06519,且整个自治块自动回滚——日志白插。
- 正常路径末尾加
COMMIT;,别省 -
EXCEPTION分支里必须写ROLLBACK;,不能只RAISE;;否则异常一出,自治事务悬空 - 嵌套调用另一个自治过程?那它也得自己管好自己的
COMMIT/ROLLBACK,外层不负责收尾
主事务异常时只调用自治过程,不碰任何 DML + COMMIT 组合
很多人在主过程的 EXCEPTION 块里直接写 INSERT INTO t_log ...; COMMIT;,以为能保住日志——但这条 INSERT 仍属于主事务,主事务一 ROLLBACK,它跟着丢。
- 真正有效的做法:把日志逻辑完全剥离,封装成自治过程,主过程里只做一次调用
- 主过程里禁止在
EXCEPTION中执行任何 DML +COMMIT组合 - 自治过程插入的数据,主事务无论
COMMIT还是ROLLBACK,它都已落地
日志内容要捕获关键上下文,别只记 SQLERRM
SQLERRM 虽然带错误码前缀(如 ORA-00001),但定位不到真实出错行。主事务未提交的数据,自治事务也查不到,所以字段设计要务实。
- 用
DBMS_UTILITY.format_error_backtrace替代$$PLSQL_LINE,能穿透嵌套调用定位到原始出错点 -
SQLCODE是负数(如-1),别做ABS()处理 - 业务标识(如单号、批次号)必须由调用方传入,自治过程不猜、不查、不关联主事务中间态
- 序列值推进不可逆:
SEQ_LOG.NEXTVAL在自治事务里调用,就真实递增,哪怕主事务最终回滚
自治事务的关键不在“自动”,而在“独立”。最容易被忽略的是声明位置和提交路径的强制性——它不接受妥协,也不容侥幸。











