1. 程式人生 > >Oracle v$LOCK

Oracle v$LOCK

為了實現併發,oracle資料庫使用了鎖機制。要了解鎖,首先要了解檢視v$lock。

v$lock這個檢視列出 Oracle 伺服器當前擁有的鎖以及未完成的鎖請求。如果你覺著 session 處於等待事件隊列當中,那你應該檢查檢視v$lock。

 

v$lock中的常用列有以下列:

     sid:持有鎖的會話SID,通常與v$session關聯。

     type:鎖的型別,其中TM表示表鎖或DML鎖,TX表示行鎖或事務鎖,UL表示使用者鎖。我們主要關注TX和TM兩種型的鎖,其它均為系統鎖,會很快自動釋放,不用關注。

當 Oracle執行 DML 語句時,系統自動在所要操作的表上申請 TM 型別的鎖。當 TM鎖獲得後,系統再自動申請 TX 型別的鎖,並將實際鎖定的資料行的鎖標誌位進行置位。

TM 鎖包括了SS 、 SX、 S 、X 等多種模式,在資料庫中用 0 -6 來表示。不同的 SQL 操作產生不同型別的 TM鎖。

 

     lmode:會話保持的鎖的模式。

          0=None;

          1=Null ;

          2=Row-S (SS,行級共享鎖,其他物件只能查詢這些資料行),sql操作有select for update、lock for update、lock row share;

          3=Row-X (SX,行級排它鎖,在提交前不允許做DML操作),sql操作有insert、update、delete、lock row share;

          4=Share(共享鎖),sql操作有create index、lock share;

          5=S/Row-X (SSX,共享行級排它鎖),sql操作有lock share row exclusive;

          6=Exclusive(排它鎖),alter table、drop table、drop index、truncate table、look exclusive等DDL

 

     ID1,ID2:  ID1,ID2的取值含義根據type的取值而有所不同。

(1)對於TM 鎖ID1表示被鎖定表的object_id 可以和dba_objects檢視關聯取得具體表資訊,ID2 值為0;

(2)對於TX 鎖ID1以十進位制數值表示該事務所佔用的回滾段號和事務槽slot number號,其組形式: 0xRRRRSSSS,RRRR=RBS/UNDO NUMBER,SSSS=SLOT NUMBER,ID2 以十進位制數值表示環繞wrap的次數,即事務槽被重用的次數。實際上這兩個欄位構成了事務在回滾段中的位置。

 

當鎖產生時,以下圖為例說明v$lock:

1、圖中存在兩個session分別是36和37,session 37的BLOCK=1意味著該session擁有一個鎖,並阻塞了其他session的對該鎖的請求(如果要處理死鎖這是根源)。該鎖的型別由TY定義,模式由LMODE欄位定義;

2、session 36的request=6說明該session正在等待一個lmode為6的鎖,而該鎖的擁有者正是session 37。

3、對於TM鎖,ID1值就是加鎖的段物件,可以是表或者表分割槽,此時ID2一般為0;對於TX鎖,這兩個欄位構成該事務在回滾段中的位置。

 

對於死鎖的處理流程:(下面過程也適合生產環境)

1,查詢鎖,阻塞的session和被阻塞session的sid:

set linesize 1200

COL USERNAME FOR A15

COL EVENT FOR A15

COL SID FOR 999999

COL INST_ID FOR 99

select inst_id,sid, username, event, blocking_session,

seconds_in_wait, wait_time

from gv$session where state in ('WAITING')

and wait_class != 'Idle';

可以看到sid為37的會話阻塞了sid為36的會話,我們要處理的是37的這個會話,將這個會話殺死。

 

2,查詢session sid對應的作業系統的spid,並且殺死會話

SQL> select  b.spid,a.sid,a.username,a.program,a.machine  from v$session a,v$process b where a.paddr=b.addr and a.type='USER';

這個sid為37的會話對應的作業系統的spid是7188,在作業系統使用者下使用root使用kill -9 7188就行了,將阻塞的會話殺掉,這樣阻塞就會消失。

 

3、批量殺死會話(如果一步到位殺死會話省去上面兩個步驟執行下面SQL語句就行)

殺阻塞的會話釋放鎖

set lines 900 pages 900  

col BLOCK for 9  

col LMODE for 9  

col INST_ID for 9  

col REQUEST for 9  

col SID for 999999  

select /*+ rule */a.INST_ID,

       a.SID,

       a.TYPE,

       LMODE,

       REQUEST,

       CTIME,

       BLOCK,

       'ps -ef |grep ' || c.spid,

       decode(LMODE, 0, null, 'kill -9 ' || c.spid) kill,

       'kill -9 ' || c.spid,

       d.sql_id,

       ID1,

       ID2

  from gv$lock a, gv$session b, gv$process c, gv$sqlarea d

 where (a.ID1, a.ID2, a.TYPE) in

       (select ID1, ID2, TYPE from gv$lock where request > 0)

   and a.sid = b.sid

   and a.inst_id = b.inst_id

   and a.inst_id = c.inst_id

   and b.inst_id = d.inst_id(+)

   and a.sid=b.sid

   and b.paddr = c.addr

   and b.sql_id = d.sql_Id(+)

 order by inst_id, lmode desc;


這個和也得到最終要殺死阻塞會話的spid,使用kill -9 7188就可以消除阻塞釋放鎖。