必须用pragma autonomous_transaction,否则日志insert会随主事务回滚而丢失;自治事务需在pl/sql块顶层声明,且内部必须显式commit或rollback。
必须用 pragma autonomous_transaction,否则日志 insert 会随主事务一起回滚,查不到任何错误痕迹。
为什么普通 INSERT + COMMIT 会导致日志丢失
在存储过程里直接 INSERT INTO log_table 再 COMMIT,这条日志语句就属于当前主事务的一部分。一旦后续发生异常、调用方执行 ROLLBACK,或者主事务被外部应用中断,这条日志也会被一并撤回。
常见错误现象:
- 主过程刚插入业务数据还没提交,日志一
COMMIT,业务数据就提前落库了 - 主过程抛出异常后
ROLLBACK,日志表空空如也,根本无法定位问题 - 触发器里写日志 +
RAISE_APPLICATION_ERROR,结果日志和触发动作全被回滚
自治事务的正确声明和使用方式
PRAGMA AUTONOMOUS_TRANSACTION 必须放在 PL/SQL 块的**最顶层声明区**,不能嵌套在 IF 或 LOOP 里;且该块内所有 DML 和 DDL 都自动纳入独立事务上下文。
实操要点:
- 声明后必须显式
COMMIT或ROLLBACK,否则退出时抛ORA-06519异常 - 日志过程里不能访问主事务未提交的数据(比如
SELECT ... FOR UPDATE主表记录) - 避免死锁:自治事务不要去锁主事务正在修改的同一行或同一表分区
- 示例结构:
CREATE OR REPLACE PROCEDURE p_log_error(
p_task_id IN VARCHAR2,
p_err_code IN VARCHAR2,
p_err_msg IN VARCHAR2
) IS
PRAGMA AUTONOMOUS_TRANSACTION; -- ← 必须放这里
BEGIN
INSERT INTO t_error_log (id, task_id, err_code, err_msg, log_time)
VALUES (seq_log.NEXTVAL, p_task_id, p_err_code, p_err_msg, SYSDATE);
COMMIT; -- ← 必须有
EXCEPTION
WHEN OTHERS THEN
ROLLBACK; -- ← 出错也要回滚自治事务自身
RAISE;
END;
在异常处理中调用自治日志的典型模式
主业务过程不应自己写日志逻辑,而应统一交由自治过程处理。关键点是:异常分支里只调用日志过程,不加任何事务控制语句。
错误写法:INSERT ...; COMMIT; 放在 EXCEPTION 块里 —— 仍属主事务
正确写法:
- 主过程里
EXCEPTION WHEN OTHERS THEN p_log_error(...); RAISE; - 确保
p_log_error是自治的,且内部完成COMMIT - 主过程继续按需
ROLLBACK或COMMIT,完全不影响日志落地
最容易被忽略的是:自治过程里漏掉 COMMIT 或 ROLLBACK,导致每次调用都报错退出,日志反而一条都写不进去。











