鎖的查詢及解鎖
?
??? Oracle中的鎖的功能很多,當然鎖的屬性不單是Oracle中所獨有的,而是在DBMS中的基礎特性所規定的。也就是說無論使用何種DBMS,其S、X、SX等鎖的基本屬性都是一致的。只是各自的實現形式上的差別。當然每個DBMS在內部實現上都會所不同,Oracle在這方面具有極大的優勢。關于這一點,可以參見Tom的《9i&10g Programming Techniques And Solutions》。下面介紹一下:
?
一、死鎖
?
??? 死鎖是指:兩個事務同時希望鎖定已經被另一事務鎖定的數據,而形成的互相等待的情況。
?
??? 舉例:
?
??? SQL-1> lock table t1 in exclusive mode; --session1對t1表加X鎖
?
??? Table(s) Locked.
?
??? SQL-2
> lock table t2 in share mode;--session2對t2表加S鎖
?
??? Table(s) Locked.
?
??? SQL-1> lock table t2 in exclusive mode; --session1對t2表加X鎖,等待
?
??? SQL-2
> lock table t1 in share mode;--session2對t1表加S鎖,等待
?
??? SQL-1>
?????????????? *
??? ERROR at line 1:
??? ORA-00060: deadlock detected while waiting for resource
??? --
最終session1中報錯產生死鎖
?
??? 注:Oracle系統會自動、有效地對死鎖進行檢測,當檢測到死鎖后會選擇一個事務退出,而另一個事務繼續。
?
?
??? 遇到死鎖時,事務接到報錯也不會自動回滾,而是繼續等待,所以只有另一個事務用戶提交,或者殺死進程才能最終解鎖。
?
?
二、鎖的查詢
?
??? 可以通過動態表v$lock和v$locked_object來查看當前鎖的情況,具體表結構:
?
?
SQL> desc v$lock
Name??? Type??????? Comments
------- ----------- -------------------------
ADDR??? RAW(4)????? 在內存中鎖定的對象的地址
KADDR?? RAW(4)????? 在內存中鎖的地址
SID???? NUMBER????? SESSION標識
TYPE??? VARCHAR2(2) 鎖類型:TX=行鎖或事務鎖;TM=表鎖或DML鎖;UL=PL/SQL用戶鎖
ID1???? NUMBER????? 鎖的第1標識號。TM-將要被鎖定的對象標識號;TX-撤銷段號碼的十進制值
ID2???? NUMBER????? 鎖的第2標識號。TM-0;TX-交換次數
LMODE?? NUMBER????? 鎖的模式:0None;1Null;2RS;3RX;4S;5SRX;6X
REQUEST NUMBER????? 會話申請的鎖的模式,與LMODE中的模式相同
CTIME?? NUMBER????? 已持有或等待鎖的時間,以秒為單位
BLOCK?? NUMBER????? 當前鎖是否阻塞另一個鎖。0不阻塞;1阻塞
?
可以通過和v$session表關聯,找出某個用戶的鎖。
?
?
SQL> desc v$locked_object
Name??????????? Type???????? Comments
--------------- ------------ -------------------------
XIDUSN????????? NUMBER?????? 回滾段號碼
XIDSLOT???????? NUMBER?????? 被鎖定的對象在撤銷段中的位置
XIDSQN????????? NUMBER?????? 序列號
OBJECT_ID?????? NUMBER?????? 被鎖定的對象的標識號
SESSION_ID????? NUMBER?????? 持有鎖的session標識號
ORACLE_USERNAME VARCHAR2(30) 持有鎖的用戶ID
OS_USER_NAME??? VARCHAR2(30) 持有所的操作系統ID
PROCESS???????? VARCHAR2(12) 操作系統進程號
LOCKED_MODE???? NUMBER?????? 鎖模式0None;1Null;2RS;3RX;4S;5SRX;6X
同理,可以關聯dba_objects表,來查找某個表現有的鎖。
?
?
SQL> desc dba_locks
Name??????????? Type???????? Comments
--------------- ------------ -------------------------
SESSION_ID????? NUMBER?????? 保持或申請鎖的session標識號
LOCK_TYPE?????? VARCHAR2(26) 鎖的類型,同v$lock.type
MODE_HELD?????? VARCHAR2(40) 保持的鎖的模式
MODE_REQUESTED? VARCHAR2(40) 申請的鎖的模式
LOCK_ID1??????? VARCHAR2(40) 鎖的第1標識號
LOCK_ID2??????? VARCHAR2(40) 鎖的第2標識號
LAST_CONVERT??? NUMBER?????? 已持有或等待鎖的時間,以秒為單位
BLOCKING_OTHERS VARCHAR2(40) 當前鎖是否阻塞另一個鎖。Not Blocking不阻塞;Blocking阻塞
?
這個表基本等同于v$lock
?
?
SQL> desc dba_waiters
Name??????????? Type???????? Comments
--------------- ------------ -------------------------
WAITING_SESSION NUMBER?????? 等待鎖(被阻塞)的session標識號
HOLDING_SESSION NUMBER?????? 保持鎖(正阻塞)的session標識號
LOCK_TYPE?????? VARCHAR2(26) 鎖的類型
MODE_HELD?????? VARCHAR2(40) 保持的鎖的模式
MODE_REQUESTED? VARCHAR2(40) 申請的鎖的模式
LOCK_ID1??????? NUMBER?????? 鎖的第1標識號
LOCK_ID2??????? NUMBER?????? 鎖的第2標識號
?
這個表是比較重要的,可以看出是哪些在等待的鎖影響了系統
?
?
SQL> desc
dba_blockers
Name??????????? Type?? Comments
--------------- ------ -------------------------
HOLDING_SESSION NUMBER 阻塞了其他session的那些session標識號
?
?
?
三、解鎖
?
-----------------------------------------------------------------------------
由sys用戶通過查詢與鎖相關的視圖來了解鎖,了解阻塞會話與被阻塞會話的sid、serial#、
用戶名及其所使用的DML操作語句。
-----------------------------------------------------------------------------
?
set pagesize 40 linesize 150
column blockers format a45
column waiters format a45
select '阻塞者('||sb.sid||':'||sb.serial#||'-'||sb.username||')-'||qb.sql_text blockers,
?????? '等待者('||sw.sid||':'||sw.serial#||'-'||sw.username||')-'||qw.sql_text waiters
from v$lock lb,v$lock lw,v$session sb,v$session sw,v$sql qb,v$sql qw
where lb.sid=sb.sid
? and lw.sid=sw.sid
? and sb.prev_sql_addr=qb.address
? and sw.sql_address=qw.address
? and lb.id1=lw.id1
? and sb.lockwait is null
? and sw.lockwait is not null
? and lb.block=1;
---------------------------------------------------------------------------
要了解哪些數據庫用戶的會話鎖定了對象、鎖定的模式是什么、對應的操作系統
用戶是在哪臺計算機上進行操作的、被鎖定的對象及其類型等信息
---------------------------------------------------------------------------
set pagesize 40 linesize 150
column username format a9
column sid format 9999
column serial# format 99999999
column mode_locked format a12
column os_user_name format a16
column object_name format a12
column object_type format a12
select s.username,s.sid,s.serial#,
???? decode(lo.locked_mode,
???? 0,'none',
???? 1,'null',
???? 2,'row-s(ss)',
???? 3,'row-x(sx)',
???? 4,'share',
???? 5,'s/row-x(ssx)',
???? 6,'exclusive',
???? to_char(lo.locked_mode)) mode_locked,
???? lo.os_user_name,
???? do.object_name,do.object_type
from v$session s,v$locked_object lo,dba_objects do
where
?? lo.object_id=do.object_id;
---------------------------------------------------------------------------
要了解阻塞者會話的sid、serial#信息
---------------------------------------------------------------------------
set pagesize 40 linesize 150
column username format a9
column sid format 9999
column serial# format 99999999
select s.username,s.sid,s.serial#
from v$session s,dba_blockers dbab
where s.sid=dbab.holding_session;
?
---------------------------------------
解鎖?????
---------------------------------------
alter system kill session 'sid,serial#';
?
-----------------------------------------------------------
declare
cursor cur_lock IS
select sid,type,lmode,request,ctime,block from v$lock;
mysid v$lock.sid%type;
mytype v$lock.type%type;
mylmode v$lock.lmode%type;
myrequest v$lock.request%type;
myctime v$lock.ctime%type;
myblock v$lock.block%type;
icount integer;
begin?
open cur_lock;
loop
fetch cur_lock into mysid,mytype,mylmode,myrequest,myctime,myblock;
?? exit when cur_lock%NOTFOUND;
?? select count(*) into icount from v$lock where sid=mysid;
?? if icount>0 then
?? insert into lock_test (sid,type,lmode,request,ctime,block) values
?? (mysid,mytype,mylmode,myrequest,myctime,myblock);
?? else?
???? dbms_output.put_line('no data');
?? end if;
end loop;
close cur_lock;
EXCEPTION
? WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20000,'ERROR trg_pets_upper_pet_kind: '|| SQLERRM);
end;
/
?
?