ora-00060不会自动回滚整个事务,仅中断当前语句,必须在exception块中显式rollback;需精准捕获sqlcode = -60、配合延时重试(≤3次)及业务层优化,如统一更新顺序、外键列建索引、避免事务内调用外部接口。

ORA-00060不会自动回滚事务,必须显式ROLLBACK
PL/SQL遇到ORA-00060时,Oracle只回滚“牺牲者”会话中**当前被中断的那条语句**,而不是整个事务。你之前执行的UPDATE、INSERT等DML仍处于未提交状态——这会导致后续语句报ORA-00068(事务状态不一致),或掩盖真实业务逻辑错误。
常见错误是依赖WHEN OTHERS THEN NULL或把ROLLBACK写在存储过程末尾。正确做法是在最内层可能触发死锁的DML后立即包围EXCEPTION块:
- 用
WHEN OTHERS THEN IF SQLCODE = -60 THEN ROLLBACK; ... END IF;,不能用WHEN DUP_VAL_ON_INDEX之类预定义异常名(ORA-00060没有对应名称) -
SQLCODE只在EXCEPTION块内有效,离开就失效 - 如果用了
PRAGMA AUTONOMOUS_TRANSACTION,主事务ROLLBACK不影响自治事务,需单独处理
重试必须加延时且限制次数,否则大概率复现死锁
死锁本质是两个会话按不同物理顺序争抢同一组行锁,直接循环重试等于让它们反复撞车。不加控制的FOR i IN 1..3 LOOP ... EXCEPTION WHEN ... THEN CONTINUE; END LOOP;会让问题恶化。
实操要点:
- 每次重试前调用
DBMS_LOCK.SLEEP(0.1)(单位秒),哪怕100ms也能错开竞争窗口 - 重试上限设为3次,超过说明业务设计有问题:比如长事务没拆分、多表更新顺序不统一、外键列缺索引
- 重试应从头开始执行完整逻辑单元,不要在循环里反复
COMMIT/ROLLBACK,破坏原子性
死锁现场已消失,查v$locked_object基本无效
ORA-00060报错瞬间,Oracle已强制回滚牺牲者事务并释放所有锁。此时查v$locked_object或DBA_WAITERS往往为空,不是监控遗漏,而是锁已被清理。
真正该看的是trace文件(路径由SELECT value FROM v$diag_info WHERE name='Diag Trace'确认),里面包含Deadlock graph,明确列出:
- 谁持有哪一行锁(
obj - rowid)、请求哪一行锁 - 另一个会话的对应持锁/等待关系
- 会话
DID和sql_id,可关联v$sql查原始SQL
别在alert日志里只扫ORA-00060字样——摘要信息没用,必须进trace文件定位具体行级冲突。
应用层不配合,PL/SQL层再精细也白搭
很多ORA-00060根子不在数据库内部,而在外部调用:
- JDBC连接没设
queryTimeout,慢查询长期占着行锁 - 事务里调用HTTP接口,网络延迟拉长锁持有时间
- 用
SELECT FOR UPDATE但没按主键排序,返回行序不确定,导致不同会话加锁物理顺序交叉
业务允许时,优先考虑把READ COMMITTED事务改成READ ONLY,彻底规避写锁竞争。死锁不是靠捕获异常就能修好的问题——它暴露的是并发访问路径的设计缺陷,比如多表更新顺序不统一、外键列无索引引发全表扫描式加锁。











