為了確保并發用戶在存取同一數據庫對象時的正確性(即無丟失修改、可重復讀、不讀
“臟”數據),數據庫中引入了鎖機制?;镜逆i類型有兩種:排它鎖(Exclusive locks 記
為X 鎖)和共享鎖(Share locks記為 S鎖)。
排它鎖:若事務T對數據D加X鎖,則其它任何事務都不能再對D加任何類型的鎖,
直至T 釋放D 上的X 鎖;一般要求在修改數據前要向該數據加排它鎖,所以排它鎖又稱為
寫鎖。
共享鎖:若事務T對數據D加S 鎖,則其它事務只能對D加 S鎖,而不能加X 鎖,直
至 T 釋放 D 上的 S 鎖;一般要求在讀取數據前要向該數據加共享鎖,所以共享鎖又稱為讀
鎖。
2.Oracle多粒度封鎖機制介紹
根據保護對象的不同,Oracle數據庫鎖可以分為以下幾大類:
(1) DML lock(data locks,數據鎖):用于保護數據的完整性;
(2) DDL lock(dictionary locks,字典鎖):用于保護數據庫對象的結構(例如表、視圖、索
引的結構定義);
(3) internal locks 和 l a t c h es(內部鎖與閂):保護內部數據庫結構;
(4) distributed locks(分布式鎖):用于OPS(并行服務器)中;
(5) PCM locks(并行高速緩存管理鎖):用于OPS(并行服務器)中。
本文主要討論DML(也可稱為data locks,數據鎖)鎖。從封鎖粒度(封鎖對象的大?。?
的角度看,Oracle DML鎖共有兩個層次,即行級鎖和表級鎖。
2.1 Oracle 的 TX 鎖(行級鎖、事務鎖)
許多對Oracle不太了解的技術人員可能會以為每一個 TX鎖代表一條被封鎖的數據行,
其實不然。 TX的本義是Transaction (事務),當一個事務第一次執行數據更改(Insert、 Update、
Delete)或使用SELECT… FOR UPDATE 語句進行查詢時,它即獲得一個TX(事務)鎖,
直至該事務結束(執行COMMIT 或ROLLBACK操作)時,該鎖才被釋放。所以,一個TX
鎖,可以對應多個被該事務鎖定的數據行。
在 Oracle 的每行數據上,都有一個標志位來表示該行數據是否被鎖定。Oracle 不象其
它一些 DBMS(數據庫管理系統)那樣,建立一個鏈表來維護每一行被加鎖的數據,這樣
就大大減小了行級鎖的維護開銷,也在很大程度上避免了其它數據庫系統使用行級封鎖時經
常發生的鎖數量不夠的情況。數據行上的鎖標志一旦被置位,就表明該行數據被加 X 鎖,
Oracle在數據行上沒有 S鎖。 2.2 TM鎖(表級鎖)
2.2.1 意向鎖的引出
表是由行組成的,當我們向某個表加鎖時,一方面需要檢查該鎖的申請是否與原有的表
級鎖相容;另一方面,還要檢查該鎖是否與表中的每一行上的鎖相容。比如一個事務要在一
個表上加 S 鎖,如果表中的一行已被另外的事務加了 X 鎖,那么該鎖的申請也應被阻塞。
如果表中的數據很多,逐行檢查鎖標志的開銷將很大,系統的性能將會受到影響。為了解決
這個問題,可以在表級引入新的鎖類型來表示其所屬行的加鎖情況,這就引出了“意向鎖”
的概念。
意向鎖的含義是如果對一個結點加意向鎖,則說明該結點的下層結點正在被加鎖;對任
一結點加鎖時,必須先對它的上層結點加意向鎖。如:對表中的任一行加鎖時,必須先對它
所在的表加意向鎖,然后再對該行加鎖。這樣一來,事務對表加鎖時,就不再需要檢查表中
每行記錄的鎖標志位了,系統效率得以大大提高。
2.2.2 意向鎖的類型
由兩種基本的鎖類型(S鎖、X 鎖),可以自然地派生出兩種意向鎖:
意向共享鎖(Intent Share Lock,簡稱 IS 鎖):如果要對一個數據庫對象加S鎖,首先
要對其上級結點加IS 鎖,表示它的后裔結點擬(意向)加 S鎖;
意向排它鎖(Intent Exclusive Lock,簡稱 IX 鎖):如果要對一個數據庫對象加X 鎖,
首先要對其上級結點加 IX鎖,表示它的后裔結點擬(意向)加X 鎖。
另外,基本的鎖類型(S、X)與意向鎖類型(IS、IX)之間還可以組合出新的鎖類型,
理論上可以組合出4種,即:S+IS,S+IX,X+IS,X+IX,但稍加分析不難看出,實際上只
有 S+IX 有新的意義,其它三種組合都沒有使鎖的強度得到提高(即:S+IS=S,X+IS=X,
X+IX=X,這里的“=”指鎖的強度相同)。所謂鎖的強度是指對其它鎖的排斥程度。
這樣我們又可以引入一種新的鎖的類型
共享意向排它鎖(Shared Intent Exclusive Lock,簡稱 SIX 鎖) :如果對一個數據庫對象
加 SIX 鎖,表示對它加 S 鎖,再加 IX 鎖,即 SIX=S+IX。例如:事務對某個表加 SIX 鎖,
則表示該事務要讀整個表(所以要對該表加S 鎖),同時會更新個別行(所以要對該表加 IX
鎖)。
這樣數據庫對象上所加的鎖類型就可能有5 種:即S、X、IS、IX、SIX。
具有意向鎖的多粒度封鎖方法中任意事務 T 要對一個數據庫對象加鎖,必須先對它的
上層結點加意向鎖。申請封鎖時應按自上而下的次序進行;釋放封鎖時則應按自下而上的次
序進行;具有意向鎖的多粒度封鎖方法提高了系統的并發度,減少了加鎖和解鎖的開銷。
2.2.3 Oracle 的 TM 鎖(表級鎖)
Oracle的 DML鎖(數據鎖)正是采用了上面提到的多粒度封鎖方法,其行級鎖雖然只
有一種(即X鎖),但其 TM鎖(表級鎖)類型共有5種,分別稱為共享鎖(S鎖)、排它鎖
(X 鎖)、行級共享鎖(RS 鎖)、行級排它鎖(RX 鎖)、共享行級排它鎖(SRX 鎖),與上面提到的S、X、IS、IX、SIX 相對應。需要注意的是,由于Oracle在行級只提供X鎖,所
以與RS鎖(通過SELECT … FOR UPDATE語句獲得)對應的行級鎖也是X鎖(但是該行
數據實際上還沒有被修改),這與理論上的IS 鎖是有區別的。
下表為Oracle數據庫TM鎖的相容矩陣(Y=Yes,表示相容的請求; N=No,表示不相
容的請求;-表示沒有加鎖請求):
T2
T1
S X RS RX SRX -
S Y N Y N N Y
X N N N N N Y
RS Y N Y Y Y Y
RX N N Y Y N Y
SRX N N Y N N Y
- Y Y Y Y Y Y
表一:Oracle 數據庫 TM 鎖的相容矩陣
一方面,當Oracle 執行SELECT…FOR UPDATE、 INSERT、 UPDATE、 DELETE等 DML
語句時,系統自動在所要操作的表上申請表級RS鎖(SELECT…FOR UPDATE)或 RX鎖
(INSERT、UPDATE、DELETE),當表級鎖獲得后,系統再自動申請 TX 鎖,并將實際鎖
定的數據行的鎖標志位置位(指向該TX鎖);另一方面,程序或操作人員也可以通過 LOCK
TABLE 語句來指定獲得某種類型的TM鎖。下表總結了 Oracle中各 SQL語句產生 TM鎖的
情況:
SQL語句 表鎖模式 允許的鎖模式
Select * from table_name…… 無 RS、RX、S、SRX、X
Insert into table_name…… RX RS、RX
Update table_name…… RX RS、RX
Delete from table_name…… RX RS、RX
Select * from table_name for update RS RS、RX、S、SRX
lock table table_name in row share mode RS RS、RX、S、SRX
lock table table_name in row exclusive mode RX RS、RX
lock table table_name in share mode S RS、S
lock table table_name in share row exclusive mode SRX RS
lock table table_name in exclusive mode X 無
表二:Oracle 數據庫 TM 鎖小結
我們可以看到,通常的 DML 操作(SELECT…FOR UPDATE、INSERT、UPDATE、
DELETE),在表級獲得的只是意向鎖(RS或 RX),其真正的封鎖粒度還是在行級;另外,
Oracle數據庫的一個顯著特點是,在缺省情況下,單純地讀數據(SELECT)并不加鎖, Oracle
通過回滾段(Rollback segment)來保證用戶不讀“臟”數據。這些都極大地提高了系統的
并發程度。
由于意向鎖及數據行上鎖標志位的引入,極大地減小了 Oracle 維護行級鎖的開銷,這
些技術的應用使Oracle 能夠高效地處理高度并發的事務請求。 3 Oracle 多粒度封鎖機制的監控
3.1 系統視圖介紹
為了監控Oracle系統中鎖的狀況,我們需要對幾個系統視圖有所了解:
3.1.1 v$lock視圖
v$lock視圖列出當前系統持有的或正在申請的所有鎖的情況,其主要字段說明如下:
字段名稱 類型 說明
SID NUMBER 會話(session)標識;
TYPE VARCHAR(2) 區分該鎖保護對象的類型;
ID1 NUMBER 鎖標識1;
ID2 NUMBER 鎖標識2;
LMODE NUMBER 鎖模式: 0 (None), 1 (null) ,2 (row share) , 3 (row exclusive) ,4
(share),5(share row exclusive),6(exclusive)
REQUEST NUMBER 申請的鎖模式:具體值同上面的LMODE
CTIME NUMBER 已持有或等待鎖的時間;
BLOCK NUMBER 是否阻塞其它鎖申請;
表三:v$lock 視圖主要字段說明
其中在TYPE 字段的取值中,本文只關心 TM、TX兩種DML鎖類型;
關于ID1、ID2,TYPE取值不同其含義也有所不同:
TYPE ID1 ID2
TM 被修改表的標識(object_id) 0
TX 以十進制數值表示該事務所占用的回滾段號與該事
務在該回滾段的事務表(Transaction table)中所占
用的槽號(slot number,可理解為記錄號)。其組成
形式為: 0xRRRrssSS ( RRRR = RBS number,
SSSS = slot )。
以十進制數值表示環繞
(wrap)次數,即該槽(slot)
被重用的次數;
表四:v$lock 視圖中 ID1與 ID2 字段取值說明
3.1.2 v$locked_object 視圖
v$locked_object視圖列出當前系統中哪些對象正被鎖定,其主要字段說明如下:
字段名稱 類型 說明
XIDUSN NUMBER 回滾段號;
XIDSLOT NUMBER 槽號;
XIDSQN NUMBER 序列號;
OBJECT_ID NUMBER 被鎖對象標識; SESSION_ID NUMBER 持有鎖的會話(SESSION)標識;
ORACLE_USERNAME VARCHAR2(30) 持有該鎖的用戶的Oracle用戶名;
OS_USER_NAME VARCHAR2(15) 持有該鎖的用戶的操作系統用戶名;
PROCESS VARCHAR2(9) 操作系統的進程號;
LOCKED_MODE NUMBER 鎖模式,取值同表三中的LMODE;
表五:v$locked_object 視圖字段說明
3.2 監控腳本
根據上述系統視圖,可以編制腳本來監控數據庫中鎖的狀況。
3.2.1 showlock.sql
第一個腳本 showlock.sql,該腳本通過連接 v$locked_object 與 all_objects 兩視圖,顯示
哪些對象被哪些會話鎖住:
/* showlock.sql */
column o_name format a10
column lock_type format a20
column object_name format a15
select rpad(oracle_username,10) o_name,session_id sid,
decode(locked_mode,0,'None',1,'Null',2,'Row share',
3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_type,
object_name ,xidusn,xidslot,xidsqn
from v$locked_object,all_objects
where v$locked_object.object_id=all_objects.object_id;
3.2.2 showalllock.sql
第二個腳本showalllock.sql,該腳本主要顯示當前所有 TM、TX鎖的信息;
/* showalllock.sql */
select sid,type,id1,id2,
decode(lmode,0,'None',1,'Null',2,'Row share',
3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive')
lock_type,request,ctime,block
from v$lock
where TYPE IN('TX','TM');
4.Oracle多粒度封鎖機制示例
以下示例均運行在Oracle 8.1.7上,數據庫版本不同,其輸出結果也可能有所不同。首
先建立3個會話,其中兩個(以下用 SESS#1、SESS#2 表示)以SCOTT用戶連入數據庫,以操作 Oracle 提供的示例表(DEPT、EMP);另一個(以下用 SESS#3 表示)以 SYS 用戶
連入數據庫,用于監控;
4.1 操作同一行數據引發的鎖阻塞
SESS#1:
SQL> select * from dept for update;
DEPTNO DNAME LOC
---------- -------------- -------------
10 account 70
20 research 8
30 sales 8
40 Operations 8
SESS#3:
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 17 Row share DEPT 8 2 5861
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
17 TX 524290 5861 Exclusive 0 761 0
17 TM 32970 0 Row share 0 761 0
如第一個腳本showlock 所示,執行完SELECT…FOR UPDATE 語句后, SESS#1(SID
為 17)在 DEPT 表上獲得 Row share 鎖;如第二個腳本 showalllock 所示,SESS#1 獲得的
TX鎖為Exclusive,這些都驗證了上面的理論分析。另外,我們可以將TX鎖的 ID1按如下
方法進行分解:
SQL> select trunc(524290/65536) xidusn,mod(524290,65536) xidslot from dual;
XIDUSN XIDSLOT
------ -------
8 2
分解結果與第一個腳本直接查出來的XIDUSN與XIDSLOT相同,而TX鎖的ID2 (5861)
與XIDSQN相同,可見當LOCK TYPE 為TX 時,ID1 實際上是該事務所占用的回滾段段號
與事務表中的槽(SLOT)號的組合,ID2 即為該槽被重用的次數,而這三個值實際上可以
唯一地標識一個事務,即TRANSACTION ID,這三個值從系統表 v$transaction 中也可查到。
另外, DEPT 表中有 4 條記錄被鎖定,但 TX 鎖只有 1 個,這也與上面的理論分析一
致。繼續進行操作:
SESS#2:
SQL> update dept set loc=loc where deptno=20;
該更新語句被阻塞,此時再查看系統的鎖情況:
SESS#3:
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN ---------- ----- --------------- --------------- ------ ------- ------
SCOTT 17 Row share DEPT 8 2 5861
SCOTT 19 Row Exclusive DEPT 0 0 0
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
17 TX 524290 5861 Exclusive 0 3462 1
17 TM 32970 0 Row share 0 3462 0
19 TM 32970 0 Row Exclusive 0 7 0
19 TX 524290 5861 None 6 7 0
在 DEPT 表上除了 SESS#1(SID 為 17)持有Row share 鎖外,又增加了 SESS#2(SID
為19)持有的Row Exclusive 鎖,但還沒有為SESS#2 分配回滾段(XIDUSN、XIDSLOT、
XIDSQN 的值均為 0);而從第二個腳本看到,SESS#2 的 TX 鎖的 LOCK_TYPE 為 None,
其申請的鎖類型(REQUEST)為 6(即 Exclusive),而其 ID1、ID2 的值與 SESS#1 所持有
的 TX 鎖的 ID1、ID2 相同,SESS#1 的 TX 鎖的阻塞域(BLOCK)為 1,這就說明了由于
SESS#1 持有的 TX 鎖,阻塞了 SESS#2 的更新操作(SESS#2 所更新的行與SESS#1 所鎖定
的行相沖突)。還可以看出,SESS#2 先申請表級的 TM鎖,后申請行(事務)級的TX 鎖,
這也與前面的理論分析一致。
下面,將SESS#1的事務進行回滾,解除對SESS#2 的阻塞,再對系統進行監控。
SESS#3:
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 19 Row Exclusive DEPT 2 10 5803
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
19 TX 131082 5803 Exclusive 0 157 0
19 TM 32970 0 Row Exclusive 0 333 0
可以看到,SESS#1 的事務所持有的鎖已經釋放,系統為SESS#2的事務分配了回滾段,
而其TX 鎖也已經獲得,并且 ID1、ID2是其真正的 Transaction ID。再將會話 2 的事務進行
回滾。
SESS#2:
SQL> rollback;
Rollback complete.
檢查系統鎖的情況:
SESS#3:
SQL> @showlock
no rows selected
SQL> @showalllock
no rows selected
可以看到,TM與TX鎖已全部被釋放。 4.2 實體完整性引發的鎖阻塞
DEPT(部門)表有如下字段 DEPTNO(部門編號),DNAME(部門名稱),LOC(部
門位置);其中DEPTNO列為主鍵。
SESS#1
SQL> INSERT INTO DEPT(DEPTNO) VALUES(50);
1 row created.
SESS#3
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 7 Row Exclusive DEPT 6 88 29
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
7 TX 393304 29 Exclusive 0 6 0
7 TM 3574 0 Row Exclusive 0 6 0
向 DEPT 表中插入一條DEPTNO 為50 的記錄后,SESS#1(SID為 7)在DEPT表上獲
得Row Exclusive鎖,并且由于進行了數據插入,該事務被分配了回滾段,獲得 TX鎖。
SESS#2
INSERT INTO DEPT(DEPTNO) VALUES(50);
這時,SESS#2(SID 為8)也向DEPT表中插入一條DEPTNO為 50的記錄,該語句被
阻塞,檢查鎖情況:
SESS#3
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 8 Row Exclusive DEPT 7 75 30
SCOTT 7 Row Exclusive DEPT 6 88 29
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
7 TX 393304 29 Exclusive 0 92 1
7 TM 3574 0 Row Exclusive 0 92 0
8 TX 458827 30 Exclusive 0 22 0
8 TM 3574 0 Row Exclusive 0 22 0
8 TX 393304 29 None 4 22 0
SESS#2 在 DEPT 表上也獲得了 Row Exclusive 鎖,同樣也獲得了回滾段的分配,得到
TX 鎖,但是由于其插入的記錄與 SESS#1 插入的記錄的 DEPTNO 均為 50,該語句成功與
否取決于 SESS#1 的事務是提交還是回滾,所以 SESS#2 被阻塞,表現為 SESS#2 以 Share
方式(REQUEST=4)等待 SESS#1 所持有的TX鎖的釋放。
這時,如果SESS#1進行回滾:
SESS#1 SQL> ROLLBACK;
Rollback complete.
SESS#2
1 row created.
SESS#3
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 8 Row Exclusive DEPT 7 75 30
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
8 TX 458827 30 Exclusive 0 136 0
8 TM 3574 0 Row Exclusive 0 136 0
SESS#2的阻塞將被解除, SESS#2 只持有原先已有的TM與TX 鎖,其等待的TX 鎖(由
SESS#1持有)也消失了。
如果SESS#1提交而不是回滾,在 SESS#2上將會出現如下提示:
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.PK_DEPT) violated 錯誤。
即發生主鍵沖突,SESS#1與SESS#2 的所有鎖資源均被釋放。
4.3 參照完整性引發的鎖阻塞
EMP(員工)表有如下字段:EMPNO(員工編號),ENAME(員工姓名),DEPTNO
(員工所在部門編號),其中 DEPTNO 列為外鍵,其父表為 DEPT。
SESS#1
SQL> insert into dept(deptno) values(60);
1 row created.
SESS#3
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 7 Row Exclusive DEPT 2 6 33
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
7 TX 131078 33 Exclusive 0 148 0
7 TM 3574 0 Row Exclusive 0 148 0
SESS#1(SID 為 7)在 DEPT 表中先插入一條 DEPTNO 為 60 的記錄,SESS#1 獲得了
DEPT表上的Row Exclusive 鎖,及一個TX鎖。
SESS#2
insert into emp(empno,deptno) values(2000,60);
被阻塞
SESS#3 SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 7 Row Exclusive DEPT 2 6 33
SCOTT 8 Row Exclusive EMP 3 20 31
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
7 TX 131078 33 Exclusive 0 228 1
7 TM 3574 0 Row Exclusive 0 228 0
8 TX 196628 31 Exclusive 0 9 0
8 TM 3576 0 Row Exclusive 0 9 0
8 TX 131078 33 None 4 9 0
SESS#2(SID 為 8)向 EMP 表中出入一條新記錄,該記錄 DEPT 值為 60(即 SESS#1
剛插入,但還未提交的記錄的DEPTNO值), SESS#2 獲得了EMP 表上的Row Exclusive 鎖,
另外由于插入記錄,還分配了回滾段及一個TX 鎖,但由于 SESS#2 的插入語句是否成功取
決于SESS#1的事務是否進行提交,所以它被阻塞,表現為 SESS#2 以Share(REQUEST=4)
方式等待SESS#1釋放其持有的 TX鎖。這時SESS#1 如果提交,SESS#2的插入也將執行成
功,而如果SESS#1 回滾,由于不符合參照完整性,SESS#2 將報錯:
SESS#2
insert into emp(empno,deptno) values(2000,60)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.FK_DEPTNO) violated - parent key not
Found
SESS#2持有的鎖也被全部釋放。
4.4 外鍵未加索引引發的鎖阻塞
EMP 表上的DEPTNO 列為外鍵,但沒有在該列上建索引。
SESS#1
SQL> delete emp where 0=1;
0 rows deleted.
SESS#3:
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 7 Row Exclusive EMP 0 0 0
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
7 TM 3576 0 Row Exclusive 0 10 0
首先SESS#1(SID為7)做了一個刪除操作,但由于條件(0=1)為永假,所以實際上
并沒有一行被刪除,從監控腳本可以看出SESS#1在 EMP 表上獲得Row Exclusive 鎖,但由于沒有實際的行被刪除,所以并沒有TX鎖,也沒有為 SESS#1分配回滾段。
SESS#2:
SQL> delete dept where 0=1;
該語句雖然也不會刪除實際數據,但卻被阻塞,查看系統的鎖情況:
SESS#3:
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 8 None EMP 0 0 0
SCOTT 7 Row Exclusive EMP 0 0 0
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
7 TM 3576 0 Row Exclusive 0 31 1
8 TM 3576 0 None 4 12 0
SESS#2申請在EMP 表上加SHARE 鎖(REQUEST=4),但該申請被SESS#1阻塞,因
為SESS#1 已經在EMP 表上獲得了Row Exclusive 鎖,與SHARE鎖不相容。
下面我們對SESS#1進行回滾后,再進行監控。
SESS#3:
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 8 Share EMP 0 0 0
SCOTT 8 Row Exclusive DEPT 0 0 0
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
8 TM 3574 0 Row Exclusive 0 16 0
8 TM 3576 0 Share 0 16 0
SESS#2在EMP 表上獲得Share鎖后,又在DEPT 表上獲得Row Exclusive 鎖,由于沒
有實際的行被修改,SESS#2 并沒有獲得TX 鎖。
在 Oracle8中,如果子表的外鍵上沒有加索引,當在父表上刪除記錄時,會先在子表上
申請獲得 Share 鎖,之后再在父表上申請 Row Exclusive 鎖。由于表級 Share 鎖的封鎖粒度
較大,所以容易引起阻塞,從而造成性能問題。
當在外鍵上建立索引后,在父表上刪除數據將不再對子表上加 Share鎖,如下所示:
SESS#1:
SQL> create index i_emp_deptno on emp(deptno);
Index created.
SQL> delete dept where 0=1;
0 rows deleted.
SQL>
SQL> @showlock
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT XIDSQN
---------- ----- --------------- --------------- ------ ------- ------
SCOTT 7 Row Exclusive DEPT 0 0 0
SQL> @showalllock
SID TY ID1 ID2 LOCK_TYPE REQUEST CTIME BLOCK
----- -- ---------- ---------- --------------- ---------- ---------- ----------
7 TM 3574 0 Row Exclusive 0 9 0
可以看到,在 EMP 表 DEPTNO 列上建立索引后,在 DEPT 表上執行 DELETE 操作,
不再要求在EMP 表上加Share鎖,只是在DEPT表上加 Row Exclusive鎖,封鎖的粒度減小,
引起阻塞的可能性也減小。
5.總結
Oracle數據庫通過具有意向鎖的多粒度封鎖機制進行并發控制,保證數據的一致性。其 DML
鎖(數據鎖)分為兩個層次(粒度):即表級和行級。通常的 DML 操作在表級獲得的只是
意向鎖(RS或RX),其真正的封鎖粒度還是在行級;另外,在Oracle數據庫中,單純地讀
數據(SELECT)并不加鎖,這些都極大地提高了系統的并發程度。
在支持高并發度的同時,Oracle數據庫利用意向鎖及數據行上加鎖標志位等設計技巧,減小了
Oracle維護行級鎖的開銷,使其在數據庫并發控制方面的優勢愈加明顯。
新聞熱點
疑難解答