Oracle PL/SQL如何处理死锁问题?

风雪酱_7557

风雪酱_7557

2026-11-02

157人浏览

原创

Oracle会自动检测死锁并回滚其中一个事务(victim),抛出ORA-00060错误;真正需人工干预的是长期持锁不释放的阻塞会话,须结合v$locked_object与v$session定位blocker,查prev_sql_id或v$sqltext还原加锁语句,并谨慎使用ALTER SYSTEM KILL SESSION IMMEDIATE。

oracle pl/sql如何处理死锁问题?

Oracle 不会“自动处理”死锁,而是由数据库引擎检测到后立即回滚其中一个事务(victim),并抛出 ORA-00060 错误。真正需要人工干预的,是那些未被自动识别为死锁、但长期持锁不释放的阻塞会话——它们常被误认为“死锁”,实则是锁等待超时或应用未提交导致的假死状态。

查 v$locked_object 和 v$session 定位真实阻塞源

死锁发生后,ORA-00060 日志里只记录 victim 信息,但 blocker 往往还在运行。光看 v$locked_object 只能知道哪些对象被锁,必须关联 v$session 才能定位到具体会话:

  • v$locked_object.session_id 对应 v$session.sid,不是 v$session.serial#
  • 用 SELECT sid, serial#, username, status, sql_id, prev_sql_id FROM v$session WHERE sid IN (SELECT session_id FROM v$locked_object) 查活跃会话
  • 注意 status = 'INACTIVE' 不代表空闲,可能正卡在未提交事务中;status = 'ACTIVE' 且 sql_id IS NULL 说明当前没执行 SQL,但事务仍开启
  • 若 lockwait 字段非空(如 0000000000000000 以外值),说明该会话正在等待某个锁,大概率是 blocker

用 v$sql 和 v$sqltext 还原阻塞 SQL

仅靠 v$session.sql_id 可能拿不到完整语句,因为事务中多条 SQL 切换后,sql_id 只保留最后执行的那条。要还原最初加锁的语句,得查 prev_sql_id 或拼接 v$sqltext:

  • 先查 SELECT prev_sql_id, prev_child_number FROM v$session WHERE sid =
  • 再用 SELECT sql_text FROM v$sql WHERE sql_id = '
    ' AND child_number = <pre class="brush:php;toolbar:false;" v_child_number>
  • 如果 prev_sql_id 为空,说明会话自登录后还没执行过任何 SQL,锁来自隐式 DML(如未提交的 UPDATE)或显式 LOCK TABLE
  • 避免直接查 v$sqltext 全表:它按 piece 分片存储,需 ORDER BY piece 拼接,且无索引,大库上慢

ALTER SYSTEM KILL SESSION 的 immediate 时机与风险

执行 ALTER SYSTEM KILL SESSION 'sid,serial#' 后,Oracle 会向目标会话发送中断信号,但该会话可能仍在清理资源。若长时间没退出(如正在写回滚段),就会报 ORA-00031: session marked for kill:

QuantOracle
QuantOracle

63个确定性量化金融计算器 + 10个通过MCP的复合工作流。期权定价、Greeks、奇异衍生品、风险指标、投资组合优化……

下载
  • 此时必须加 IMMEDIATE: ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE
  • IMMEDIATE 强制终止会话进程,不等事务回滚完成,后续由 PMON 进程异步清理——这会导致短暂的锁残留和回滚段压力上升
  • 不要在 RAC 环境中只查本地 v$session 就杀会话:需确认 inst_id,否则可能杀错节点上的会话
  • 杀之前先查 v$transaction:若 used_ublk > 0,说明事务已占用大量回滚块,强制杀可能延长恢复时间

为什么 SELECT ... FOR UPDATE 容易引发误判死锁

开发常把 SELECT ... FOR UPDATE 当作“加锁检查”,但没配 WAIT 或 NOWAIT,结果一执行就无限挂起,看起来像死锁:

  • 默认行为是无限等待,直到锁释放或超时(由 enqueue_resources 参数隐式控制)
  • 正确做法是显式设等待时间:SELECT * FROM emp WHERE empno = 7499 FOR UPDATE WAIT 3,超时抛 ORA-30006
  • 更安全的是用 NOWAIT + 应用层重试逻辑:SELECT * FROM emp WHERE empno = 7499 FOR UPDATE NOWAIT,失败立刻返回,由业务决定是否重试或提示用户
  • 注意:同一事务内多次 FOR UPDATE 不会报错,但若跨会话更新同一行,第二个会话会阻塞——这不是死锁,只是正常锁等待

最易被忽略的点:死锁图(deadlock graph)只出现在 alert 日志里,且默认只记录 victim 侧信息;blocker 的完整上下文(如是否在 PL/SQL 匿名块里、是否调用了自治事务)往往需要结合 v$session_longops 和会话跟踪(DBMS_MONITOR.SESSION_TRACE_ENABLE)才能还原。别只盯着 ORA-00060 报错本身。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

oracle

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4683

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

971

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1229

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6681

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3423

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6660

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

9201

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1250

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1092

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程