自治事务日志必须显式COMMIT,否则自动回滚;异常时需ROLLBACK;错误堆栈须在主异常块中用FORMAT_ERROR_BACKTRACE捕获并传参;日志表应分区、用CLOB存堆栈、建复合索引;自治事务不可见主事务未提交的GTT数据。
自治事务日志必须显式 COMMIT,否则日志白写
自治事务(pragma autonomous_transaction)本质是独立于主事务的新事务分支,它不会自动提交。如果在自治过程中只执行 insert 而不 commit,退出时 oracle 会自动回滚所有变更——日志表里查不到任何记录,但主事务回滚与否已无关紧要。
常见错误是把 COMMIT 写在异常处理外、又没兜底 ROLLBACK,导致部分路径下既没提交也没回滚,语句卡住或报 ORA-06519(检测到活动自治事务)。
- 必须在自治过程的正常路径末尾加
COMMIT - 必须在
EXCEPTION块中加ROLLBACK(不能只靠DBMS_OUTPUT打印) - 不要依赖包级变量或外部
COMMIT,自治事务生命周期完全由自身控制
SQLERRM 只有一行,堆栈信息必须在主异常块里捕获
直接传 SQLERRM 到自治日志过程,只能拿到类似“ORA-01403: no data found”这种摘要,没有出错位置。而 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 能返回真实行号,但它**只能在引发异常的同一作用域内调用**——一旦进到自治事务里,上下文已丢失,再调就返回空或误导信息。
正确做法是在主过程的 EXCEPTION 块里先收集完整信息,再作为参数传入自治过程:
EXCEPTION
WHEN OTHERS THEN
log_pkg.saveline(
p_code => SQLCODE,
p_text => SQLERRM || CHR(10) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,
p_proc => $$PLSQL_UNIT
);
END;
-
$$PLSQL_UNIT可带出当前包/过程名,比硬编码字符串更可靠 - 避免在自治过程里再次调用
FORMAT_ERROR_BACKTRACE - 若需区分错误类型,可额外传
p_level(如 'ERROR' / 'WARN')用于后续筛选
日志表设计要考虑并发与查询效率
小系统用单表 + 索引够用;高并发场景下,INSERT 集中写入同一数据块会引发缓冲区忙等待(buffer busy waits)。分区不是银弹,但按时间(如 created_on)分区能显著提升历史日志归档和冷热分离效率。
字段设计上,别省略关键元数据:
- 必加
created_on(TIMESTAMP类型,精度优于DATE) - 建议加
session_id(SYS_CONTEXT('USERENV', 'SESSIONID')),方便关联追踪 - 避免
VARCHAR2(4000)存堆栈——超长内容会被截断,改用CLOB并配LOGGING表空间 - 索引至少覆盖
(created_on, error_code),支持按时间范围+错误码快速下钻
自治事务不能访问主事务未提交的临时表数据
这是容易被忽略的隔离限制:主事务里建了全局临时表(GLOBAL TEMPORARY TABLE)并插入数据,自治事务中去查这张表,结果为空——哪怕主事务还没结束。因为自治事务启动时开启的是新一致性读视图,看不到未提交变更。
典型踩坑场景:
- 业务逻辑把中间结果暂存在 GTT,再统一记日志 → 日志过程查不到数据,误判为“无中间状态”
- 触发器里调用自治日志 → 若触发器本身基于 GTT 或未提交 DML,日志内容可能缺失关键上下文
- 解决方案:把需要记录的临时数据作为参数显式传入日志过程,而非让日志过程反向查询
自治事务的“独立性”是双刃剑:它保住了日志不被主事务拖垮,但也切断了对主事务运行时状态的直接感知。参数传递比跨事务查询更可控。











