Oracle鎖2:DML操作和鎖
Oracle為DML操作自動獲取行鎖和表鎖,操作的類型決定了鎖的行為,下面對DML操作鎖的情況作了一個匯總:
SQL Statement |
Row Locks |
Table Lock Mode |
RS |
RX |
S |
SRX |
X |
SELECT ... FROM table...
——
none
Y
Y
Y
Y
Y
INSERT INTO table ...
Yes
SX
Y
Y
N
N
N
UPDATE table ...
Yes
SX
Y(注)
Y(注)
N
N
N
MERGE INTO table ...
Yes
SX
Y
Y
N
N
N
DELETE FROM table ...
Yes
SX
Y(注)
Y(注)
N
N
N
SELECT ... FROM tableFORUPDATEOF ...
Yes
SX
Y(注)
Y(注)
N
N
N
LOCK TABLE tableIN ...
——
ROW SHARE MODE
SS
Y
Y
Y
Y
N
ROW EXCLUSIVE MODE
SX
Y
Y
N
N
N
SHARE MODE
S
Y
N
Y
N
N
SHARE ROW EXCLUSIVE MODE
SSX
Y
N
N
N
N
EXCLUSIVE MODE
X
N
N
N
N
N
注:如果另一個事務和當前事務出現行沖突,則需要等待
下面闡述當行被查詢和修改時會涉及到的鎖。
當行被查詢時的鎖
一個查詢可以直接通過SELECT查詢數據,或者其它語句間接的查詢數據,如:INSERT、MERGE、UPDATE和DELETE,其中只有INSERT操作不是必定會涉及到查詢的。因為查詢僅讀數據,因此他們被其它DML語句干涉的可能性是最小的。
如果查詢沒有FOR UPDATE子句,則查詢時:
1)查詢不要求數據鎖,因此,其它事務能查詢和更新正在被查詢的數據;
2)查詢不必等待任何數據鎖被釋放,因此,查詢總是能執行。一個例外是查詢必須等待分布式事務的一些特定的數據鎖。
當行被修改時的鎖
一些數據庫使用一個內存中的列表來維護鎖,但Oracle數據庫存儲鎖信息在數據塊中,信息包含了被鎖的行,每個行鎖僅影響一行數據。
Oracle數據庫為行鎖的獲取使用了一個隊列機制,如果一個事務請求一個行鎖,並且行未被鎖,那麼事務獲取行的數據塊的一個鎖,事務自身會在數據塊頭的interested transaction list(ITL)區域放一個條目,被事務修改的每一行都指向ITL中存儲的事務ID的一個拷貝,因此,被單個事務修改的在同一塊中的100行數據會要求100個行鎖,但是所有100行都引用同一個事務ID。
當事務結束時,事務ID保留在數據塊頭的ITL區域中。如果一個新的事物想修改一行,那麼它使用事務ID判斷該鎖是否是激活的,如果鎖是激活的,那麼新事務的session會請求在鎖被釋放時被通知,否則,新事務獲取鎖。
INSERT、UPDATE、DELETE和SELECT ... FOR UPDATE將滿足:
1)使用這些DML操作的事務將在修改的行上請求排它行鎖,因此,其它事務不能更新或者刪除鎖定的行,直到事務commit或者roll back;
2)除了行鎖,使用這些DML操作的事務至少需要請求一個子排它表鎖(subexclusive table lock,SX)。如果事務已經擁有了一個S、SRX或者X表鎖(比SX鎖有更強的限制),那麼SX鎖不被需要;如果事務已經擁有了一個SS鎖,那麼Oracle數據庫自動轉換SS鎖到SX鎖;
3)除非涉及的行被修改,事務不會對任何子查詢或者隱含的子查詢涉及的行加行鎖;例如下面的update操作,使用那個了一個子查詢(括號中的部分)和隱含子查詢(WHERE a > 5):
UPDATE t SET x = ( SELECT y FROM t2 WHERE t2.z = t.z ) WHERE a > 5;
事務將不會對子查詢(SELECT y FROM t2 WHERE t2.z = t.z)涉及的行加鎖。
4)在同一個事務中,一個查詢能看到先前的DML語句修改的行,但不能看到其它事務未提交的改變。