㈠ 單一實例Oracle locking機制
locking機制的三大組成部分:
① resource structure
Oracle對於每個需要“並發訪問”的資源,都在SGA中用一個資料結構來描述它
這個結構叫resource structure
這個資料結構有三個成員:owner、waiter和converter
這是3個指標
指向由lock structure組成的鏈表的指標
其中,converter和waiter有些區別:
如果某個操作先後需要兩種不同模式的鎖,比如,先S,後X,則進程會先請求S,獲得後lock structure會掛在owner上,
當需要X時,進行必須先釋放S,然後再次申請X
但是可能無法立即獲得
這時這個請求會被立即掛在converter下
converter的優先順序高於waiter
根據v$lock的lmode和request可以判斷他三:
● lmode > 0,request =0 → owner
● lmode = 0,request >0 → waiter
● lmode > 0,request >0 → converter
② lock structure
每當進程要訪問共用資源時,必須先鎖定該資源
鎖定實際就是從SGA中申請一個lock structure
在其中記錄lmode 、PID等
然後看能否立刻獲得該資源的訪問權
● 如果能,則把lock structure掛到resource structure的owner鏈表中
● 否則,把這個lock structure掛到resource structure的waiter鏈表中
③ enqueue演算法
按先入先出原則分配鎖
㈡ 行級鎖
以上的locking機制需要resource、lock兩種資料結構,適合粗粒度資源,但對於資料記錄等細粒度的訪問,無論從
記憶體需求還是維護成本,都是一個惡夢
Oracle的行級鎖就是在這種場合下閃亮登場的
行級鎖不是Oracle一般意義上的鎖
雖然有鎖的功能,但是沒有鎖的開銷
行級鎖根本沒有相關開銷,對1千萬行鎖定所需的資源數與對1行鎖定所需的資源數完全相同,這是個常量:0和1
在Oracle的每行資料上,都有一個標誌位來表示該行資料是否被鎖定,要查看某一行是否被鎖定,必須直接找到這一行,
而不要指望能從哪個列表得到答案
我們dump一個資料區塊,其transaction header的trc檔案摘錄如下:
Block header dump: 0x01000197 Object id on Block? Y seg/obj: 0xcd8a csc: 0x00.a26fe itc: 2 flg: E typ: 1 - DATA brn: 0 bdba: 0x1000191 ver: 0x01 opc: 0 inc: 0 exflg: 0 Itl Xid Uba Flag Lck Scn/Fsc0x01 0x0001.005.00000100 0x0080000f.00ae.23 --U- 1 fsc 0x0000.000a27070x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
其中 Lck欄位就是行級鎖的表示:1加鎖,0不加鎖
data header的部分trc摘錄如下:
tab 0, row 0, @0x1f93 tl: 5 fb: --H-FL-- lb: 0x1 cc: 1 col 0: [ 1] 61
其中 lb => ITL number
其實,lb就是Itl
並發訪問時,事務通過這個lb找到Itl,從而確定Lck的值,若為1,則掛到隊列池
所以,當使用者被阻塞時,不是被某條記錄的行級鎖阻塞,而是被TX鎖阻塞
下面用實驗證明之:
session_A
sys@ORCL> drop table t purge;Table dropped.sys@ORCL> create table demo (id number,name varchar2(10));Table created.sys@ORCL> insert into demo values(1,'bin');1 row created.sys@ORCL> insert into demo values(2,'think');1 row created.sys@ORCL> insert into demo values(3,'water');1 row created.sys@ORCL> commit;Commit complete.sys@ORCL> select * from demo; ID NAME---------- ---------- 1 bin 2 think 3 watersys@ORCL> savepoint a;Savepoint created.sys@ORCL> update demo set name='think big' where id=2;1 row updated.
session_B
在session_B,並發修改同一條記錄,會話被阻塞
sys@ORCL> update demo set name='think big' where id=2; --被阻塞
此時在session_A復原到之前的savepoint,這相當於撤銷了對記錄的修改
但是session_B仍然處於等待狀態
這是因為session_B是被session_A的TX鎖阻塞,而不是被session_A的行級鎖阻塞
在session_C上進行查詢:
sys@ORCL> select sid,lmode,request from v$lock where sid in (1081,1090); SID LMODE REQUEST---------- ---------- ---------- 1090 0 6 1081 3 0 1090 3 0 1081 6 0sys@ORCL> select sid,event from v$session where sid in (1081,1090); SID EVENT---------- ---------------------------------------------------------------- 1081 SQL*Net message from client 1090 enq: TX - row lock contention