oracle 11查询数据库锁
在 Oracle 数据库中,如果一个 UPDATE 语句被阻塞(即长时间“挂起”不返回),通常是因为它试图修改的行已被另一个会话锁定(尚未提交或回滚)。要诊断阻塞原因,可以按以下步骤进行:
🔍 一、确认是否存在阻塞
1. 查看当前被阻塞的会话(等待中的会话)
SELECT sid,serial#,username,sql_id,event,blocking_session, -- 阻塞当前会话的会话 IDseconds_in_wait,state
FROM v$session
WHERE blocking_session IS NOT NULL;
- 如果
blocking_session不为NULL,说明该会话正在被其他会话阻塞。 event字段通常显示'enq: TX - row lock contention',表示行锁等待。
🔗 二、定位阻塞源头(持有锁的会话)
2. 根据 blocking_session 找到阻塞者
假设上面查出被阻塞的会话是 SID=123,其 blocking_session=456,那么查看阻塞者信息:
SELECT sid,serial#,username,osuser,machine,program,status,sql_id,prev_sql_id
FROM v$session
WHERE sid = 456; -- 替换为实际的 blocking_session 值
注意:阻塞者通常是执行了 DML(如 UPDATE/DELETE)但未提交的会话。
📜 三、查看阻塞者正在执行的 SQL
3. 通过 sql_id 或 prev_sql_id 查看具体 SQL 语句
SELECT sql_text
FROM v$sql
WHERE sql_id = '...'; -- 替换为阻塞者的 sql_id 或 prev_sql_id
- 如果
sql_id为空,可尝试用prev_sql_id。 - 这能帮你确认是哪条语句持有了锁(比如一个未提交的 UPDATE)。
🧱 四、查看锁的具体信息(可选)
4. 查询 v$lock 视图了解锁类型和模式
SELECT l1.sid AS blocking_sid,l2.sid AS waiting_sid,l1.type,l1.lmode AS blocking_lmode,l2.request AS waiting_request
FROM v$lock l1, v$lock l2
WHERE l1.block = 1 -- 表示该锁正在阻塞别人AND l2.request > 0 -- 表示该会话在请求锁AND l1.id1 = l2.id1AND l1.id2 = l2.id2;
type = 'TX'表示事务锁(最常见于行级锁冲突)。lmode = 6表示排他锁(X 锁)。request = 6表示正在请求排他锁。
🛠️ 五、处理建议
✅ 正常做法:
- 联系持有锁的用户(通过
machine,osuser,program定位),让其 COMMIT 或 ROLLBACK。 - 如果是应用连接池中的“僵尸事务”,可能需要 DBA 干预。
⚠️ 强制终止(谨慎使用):
如果确认阻塞会话已异常(如客户端断开但事务未结束),可 kill 会话:
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
-- 例如:
ALTER SYSTEM KILL SESSION '456,12345' IMMEDIATE;
⚠️ 注意:强制 kill 会导致事务回滚,可能影响业务一致性。
💡 补充:如何避免此类问题?
- 应用程序应 及时提交或回滚事务,避免长事务。
- 避免在交互式工具(如 SQL*Plus、PL/SQL Developer)中执行 DML 后不提交。
- 使用
SELECT ... FOR UPDATE NOWAIT或WAIT n明确控制锁等待行为。
📌 总结
| 步骤 | 目的 |
|---|---|
1. 查 v$session(blocking_session IS NOT NULL) | 找出被阻塞的会话 |
2. 根据 blocking_session 查阻塞者 | 定位谁持有锁 |
3. 查 v$sql 获取阻塞者的 SQL | 知道是哪条语句没提交 |
4. (可选)查 v$lock 确认锁细节 | 深入分析锁类型 |
| 5. 联系用户或 kill 会话 | 解决阻塞 |
通过以上方法,你可以快速定位并解决 Oracle 中 UPDATE 被阻塞的问题。
