如何查找被锁的表到底是哪一行被锁定了

本文介绍如何通过Oracle数据库的v$session视图和DBMS_ROWID包确定被锁定的具体行位置,包括解析v$session中相关字段的意义及使用DBMS_ROWID.ROWID_CREATE过程创建ROWID。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
如何查找被锁的表到底是哪一行被锁定了
简单的总结一下。
首先v$session中的这几个字段的含义分别为
row_wait_row#---被锁定行的rownum,但是准确的说是对应的于rowid的rownum,并非是单纯的rownum。下面再详细的说。    
row_wait_obj#---row_wait_row#对应的rowid所在的表的object id。
row_wait_file#-- row_wait_row#对应的rowid所在的数据文件id
row_wait_block#--row_wait_row#对应的rowid所在的block的id
只有一个session等待另一个session的时候,这几个列的值才是有效的。
想要知道某一个表具体被锁定的是哪一行,可以利用上面这几个值,查找出被锁定行的rowid。
使用dbms_rowidb包的一个子过程(Subprograms)rowid_create
DBMS_ROWID.ROWID_CREATE (
   rowid_type    IN NUMBER,
   object_number IN NUMBER,
   relative_fno IN NUMBER,
   block_number IN NUMBER,
   row_number    IN NUMBER)
RETURN ROWID;
其中rowid_type的取值为 0 表示生成一个restricted ROWID(pre-oracle8 format); 取值为1 表示生成一个extended ROWID.
object_number取值是dba_objects视图中的data_object_id,并不是object_id,也就是说不能用row_wait_obj#.
relative_fno取值是Relative文件号,在dba_data_files里可以查到
block_number取值是数据文件的块号,也就是v$session中的row_wait_block#的值
row_number通过rowid对应出来的rownum,也就是row_wait_row#的值。
通过使用
select DBMS_ROWID.ROWID_CREATE(1,data_object_id,relative_fno,row_wait_block#,row_wait_row#) from dual;
查找出的rowid即为被锁定的行。
如果有多行数据被锁定,row_wait_row#显示的是靠''前''的行。
例子:
16:13:06 SQL> select * from test;
         A          B          C
---------- ---------- ----------
       600        600        600
       100        100        100
       100        100        100
       300        600        300
       100        100        100
       100        100        100
       500        500        500
       300        600        300
       100        100        100
       300        600        300
       100        100        100
       300        600        300
       500        500        500
       900        300        900
session1;   update test set b=300 where a=900;
session2:   update test set b=300 where a=900;
16:12:14 SQL> select row_wait_file#,row_wait_obj#,row_wait_block#,row_wait_row# from v$session where username = 'TEST';
ROW_WAIT_FILE# ROW_WAIT_OBJ# ROW_WAIT_BLOCK# ROW_WAIT_ROW#
-------------- ------------- --------------- -------------
             1            -1               0             0
             4          6728             178            21
16:11:06 SQL> select data_object_id from dba_objects where object_id = 6728;
DATA_OBJECT_ID
--------------
          6822
16:12:34 SQL> select DBMS_ROWID.ROWID_CREATE(1,6822,4,178,21) from dual;
DBMS_ROWID.ROWID_C
------------------
AAABqmAAEAAAACyAAV
16:12:51 SQL> select * from test where rowid = chartorowid('AAABqmAAEAAAACyAAV');
    A          B       C
--------- ---------- ----------
900        300    900                         

16:13:11 SQL>

通过杀数据库进程来解表
select * from V$LOCKED_OBJECT
select object_name as 对象名称,s.sid,s.serial#,p.spid as 系统进程号
from v$locked_object l , dba_objects o , v$session s , v$process p
where l.object_id=o.object_id and l.session_id=s.sid and s.paddr=p.addr;
sid及serial#为第一步查出来的数据
alter system kill session '151,52574';

<think>好的,我现在需要解决用户的问题:Oracle数据库中,orcl的记录被另一个用户住,而且里只有一行数据被。用户想知道如何解决这个问题。 首先,我需要回忆一下Oracle的相关知识。当一条记录被锁定时,通常是因为某个事务正在对该行进行操作,比如更新或删除,但还没有提交或回滚。这种情况下,其他会话如果尝试修改同一行数据,就会被阻塞,直到原事务释放。 用户提到里只有一行数据被,这可能意味着锁定的是特定的行,而不是整个。这时候需要找到是哪个会话持有这个,然后决定如何处理,比如等待它完成,或者终止该会话。 接下来,我需要考虑解决步骤。首先,确认的存在,查询数据库中的信息。常用的视图有v$session、v$locked_object、dba_blockers等。可能需要用SQL语句来查找锁定对象和会话信息。 然后,根据查询结果找到具体的会话ID(SID)和序列号(SERIAL#),如果确定该会话是异常或长时间未提交的事务,可能需要手动终止该会话。使用ALTER SYSTEM KILL SESSION命令。 另外,用户可能没有DBA权限,这时候可能需要联系数据库管理员来处理。同时,还要注意在终止会话前,确认该会话是否可以安全终止,避免影响业务。 另外,如果应用中存在未提交的事务导致遗留,可能需要检查应用程序代码,确保事务及时提交或回滚。设置合理的超时机制,或者使用SELECT FOR UPDATE NOWAIT来避免长时间等待。 用户可能还关心如何预防这种情况,比如优化事务处理,减少长事务,或者监控情况。可以建议使用监控工具或脚本定期检查状态。 现在,我需要将这些步骤整理成清晰的中文回答,分步骤说明解决方法,确保用户能逐步操作,并理解每个步骤的意义。同时,注意使用正确的术语和命令,比如正确的Oracle视图和SQL语句。 需要注意的是,用户可能对Oracle管理不太熟悉,所以需要解释每个步骤的作用,例如为什么要查询v$locked_object,如何解读查询结果等。同时,提醒用户在操作时的注意事项,比如终止会话的风险。 最后,总结解决方法和预防措施,帮助用户全面解决问题并避免再次发生。</think>以下分步骤解决Oracle行级问题: --- ### **问题定位** #### **1. 确认被对象** ```sql -- 查看当前被对象(DBA权限) SELECT a.sid, a.serial#, a.username, a.osuser, a.machine, b.object_name, c.sql_text FROM v$session a, dba_objects b, v$sql c WHERE a.sid IN (SELECT session_id FROM v$locked_object) AND b.object_id = (SELECT object_id FROM v$locked_object WHERE session_id = a.sid) AND a.sql_address = c.address(+); ``` #### **2. 定位具体行** ```sql -- 获取行级详细信息(需要ROWID) SELECT dbms_rowid.rowid_create(1, data_object_id, relative_fno, block_id, row_number) AS rowid_str FROM dba_objects, v$locked_object WHERE object_name = 'YOUR_TABLE_NAME'; -- 替换为实际名 ``` --- ### **解决方案** #### **方案1:等待自动释放** ```sql -- 查看等待时间 SELECT sid, seconds_in_wait, blocking_session FROM v$session WHERE state = 'WAITING' AND wait_class = 'Application'; ``` - **适用场景**:正常业务操作中的短暂等待 - **风险提示**:超过`enq: TX - row lock contention`默认超时时间(通常300秒)会报`ORA-00060` #### **方案2:强制终止会话** ```sql -- 终止锁定会话(需要DBA权限) ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE; -- 示例(假设查询结果sid=135,serial#=12345) ALTER SYSTEM KILL SESSION '135,12345' IMMEDIATE; ``` - **注意**:会触发`ORA-00028`错误在目标会话,需确保不影响关键业务 #### **方案3:提交/回滚事务** ```sql -- 通过会话信息联系相关用户 SELECT sid, sql_id, taddr FROM v$session WHERE sid = &blocking_sid; -- 查看对应事务 SELECT xid, status FROM v$transaction WHERE addr = (SELECT taddr FROM v$session WHERE sid = &blocking_sid); ``` --- ### **特殊场景处理** #### **场景1:分布式事务** ```sql -- 查看未决事务 SELECT * FROM dba_2pc_pending; -- 强制提交分布式事务 COMMIT FORCE 'transaction_id'; -- 强制回滚 ROLLBACK FORCE 'transaction_id'; ``` #### **场景2:物化视图刷新** ```sql -- 终止物化视图刷新进程 BEGIN dbms_mview.refresh('MV_NAME', method => '?', atomic_refresh => FALSE); END; ``` --- ### **预防措施** #### **1. 应用层优化** ```sql -- 使用NOWAIT机制 SELECT * FROM table_name FOR UPDATE NOWAIT; -- 设置等待超时 ALTER SESSION SET ddl_lock_timeout = 30; -- 单位秒 ``` #### **2. 监控配置** ```sql -- 创建监控 CREATE TABLE lock_audit ( event_time TIMESTAMP, object_name VARCHAR2(30), sid NUMBER, sql_text CLOB ); -- 设置触发器 CREATE OR REPLACE TRIGGER lock_audit_trigger AFTER LOCK ON DATABASE DECLARE v_sql CLOB; BEGIN SELECT sql_fulltext INTO v_sql FROM v$sql WHERE sql_id = (SELECT sql_id FROM v$session WHERE sid = sys_context('userenv','sid')); INSERT INTO lock_audit VALUES (SYSTIMESTAMP, sys.dictionary_obj_name, sys_context('userenv','sid'), v_sql); END; ``` #### **3. 资源限制** ```sql -- 设置用户资源限制 ALTER PROFILE app_user LIMIT idle_time 1800 -- 30分钟无操作自动断开 sessions_per_user 5; ``` --- ### **诊断工具** #### **1. ASH分析** ```sql -- 查看历史信息 SELECT sample_time, session_id, sql_id, event, blocking_session FROM dba_hist_active_sess_history WHERE event = 'enq: TX - row lock contention'; ``` #### **2. SQL Trace分析** ```sql -- 开启跟踪 EXEC DBMS_MONITOR.session_trace_enable(session_id => 123, serial_num => 456); -- 分析trace文件 tkprof ora_12345.trc output.txt sys=no aggregate=yes ``` --- > **关键要点** > 1. 优先使用`v$locked_object`与`v$session`定位源 > 2. 强制终止会话前必须确认事务性质 > 3. 长期解决方案应优化事务设计 > 4. 生产环境慎用`KILL SESSION`,建议先尝试联系用户 通过以上步骤,可以系统性地诊断和解决单行记录被的问题,同时建立预防机制降低发生概率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值