Oracle 自治事务 Autonomous Transaction 是什么?为什么常用于日志记录?
简化版
自治事务是 Oracle PL/SQL 中独立于主事务提交和回滚的事务。常用于审计或错误日志记录:即使主事务回滚,日志也可以单独提交。但它会打破普通事务直觉,不能滥用到核心业务更新。
详细版
通过 PRAGMA AUTONOMOUS_TRANSACTION 可以让过程、函数或触发器中的一段逻辑开启独立事务。
CREATE OR REPLACE PROCEDURE log_error(p_msg VARCHAR2) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO error_log(msg, created_at) VALUES (p_msg, SYSDATE);
COMMIT;
END;
主事务失败回滚时,自治事务已经提交的日志不会回滚。优点是日志可靠;风险是业务一致性变复杂、死锁和读一致性问题更隐蔽。
完整版教学
一、自治事务解决什么问题
普通事务里,业务更新和日志插入同生共死。如果业务最后回滚,日志也会消失。可是很多时候,我们恰恰希望失败日志保留下来。
自治事务允许日志过程自己提交,不受外层事务回滚影响。这对审计、错误诊断、异常追踪很有用。
主事务:扣库存 -> 失败 -> ROLLBACK
自治事务:写错误日志 -> COMMIT
结果:库存回滚,日志保留
二、基本写法
在 PL/SQL 块里声明:
PRAGMA AUTONOMOUS_TRANSACTION;
示例日志过程:
CREATE OR REPLACE PROCEDURE write_audit(p_action VARCHAR2) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO audit_log(action, created_at)
VALUES (p_action, SYSDATE);
COMMIT;
END;
自治事务内部必须自己 COMMIT 或 ROLLBACK,不能依赖外层事务收尾。
三、为什么它会打破事务直觉
外层事务还没提交,自治事务就可以提交自己的数据。这意味着数据库里会出现“日志已存在,但主业务最终没成功”的情况。
这对日志是合理的,因为日志记录的是“发生过一次尝试”;但对业务表就危险了。比如在自治事务里扣余额,外层订单回滚后余额仍扣了,一致性就坏了。
所以自治事务适合旁路记录,不适合核心业务状态。
四、读一致性和锁的影响
自治事务是独立事务,它和主事务之间也要遵守读一致性和锁规则。自治事务不一定能看到外层未提交的数据。
如果自治事务访问主事务已经锁住的资源,还可能产生等待甚至死锁。比如主事务更新某行后,触发器里的自治事务又去更新同一行,就很危险。
| 用法 | 风险 |
|---|---|
| 写独立日志表 | 相对安全 |
| 更新主业务表 | 一致性风险高 |
| 访问外层锁定行 | 等待或死锁 |
| 在触发器里复杂操作 | 排查困难 |
五、日志表设计也要配合
自治事务日志表最好独立、简单、少外键,避免因为日志写入失败影响主流程。日志字段可以包含请求号、业务单号、错误码、堆栈摘要和时间。
如果每秒 2000 次失败都写自治事务日志,日志表也会成为热点。因此仍要考虑索引、分区、归档和采样。
自治事务不是“免费保留日志”,只是改变提交边界,性能成本还在。
六、常见误区与追问
- 误区:自治事务能让业务更安全。 它会让提交边界变复杂,核心业务更新反而更危险。
- 误区:自治事务会跟随主事务回滚。 它独立提交,主事务回滚不影响已提交结果。
- 误区:自治事务里不用提交。 自治事务内部必须显式提交或回滚。
- 追问:为什么适合写日志? 因为日志记录失败尝试,即使主事务回滚也要保留。
- 追问:在触发器里用自治事务有什么风险? 容易隐藏副作用、制造锁等待和一致性困惑。
七、加强记忆
记忆钩子:自治事务像旁边单独记账的小本子,主账本撕掉了,小本子上的事故记录还在;但别用小本子直接改主账。
回答这题要讲“独立提交边界、日志用途、业务风险、锁和读一致性”。自治事务很强,但越强越要讲克制。