創建測試表
create>aaa@AAAUSORACLECOM>create table test (a numberb number)
表已創建
對於未提交的insert操作
insert>aaa@AAAUSORACLECOM>insert into test values()
已創建 行
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
AB ABA TM
AF AF TX
可見對於未提交的insert操作會產生兩個鎖其類型(TYPE)分別為TM和TX也就是表級意向鎖和事務鎖
表級意向鎖的模式(LMODE)為表示是row exclusive即表示此表中的某行獲得了行排他鎖
事務鎖的模式(LMODE)為 表示是exclusive即排他鎖表示此事務獲得了排他鎖
BLOCK表示此鎖是否阻塞了其它的鎖即發生死鎖此處沒有
對於提交的insert操作
commit>aaa@AAAUSORACLECOM>commit
提交完成
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
此處已沒有記錄說明在提交後即完成了鎖的釋放
對於未提交的update操作
update>aaa@AAAUSORACLECOM>update test set a= where a=
已更新 行
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
AB ABA TM
AF AF TX
可見update操作所引起的鎖的信息完全等同於insert操作……
對於提交的update操作
commit>aaa@AAAUSORACLECOM>commit
提交完成
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
此處已沒有記錄說明在提交後即完成了鎖的釋放
對於select操作
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>select * from test where a=;
A B
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
此處已沒有記錄說明select操作不會引起任何鎖
這是與sql server等數據庫不同的這些數據庫select操作也會引起鎖以取得一致讀
而oracle是通過回滾機制實現一致讀的所以不需要引入鎖機制這極大增強了oracle的並發度
for update操作
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>select * from test for update;
A B
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
AB ABA TM
AF AF TX
可見for update操作會引起兩個鎖分別是表級意向鎖(TM)和事務鎖(TX)
表級意向鎖鎖定模式為(row share)這表示屬於此表中的某行獲得了共享鎖相比較DML操作此處鎖級別低了一級DML的是其實在oracle中沒有行級共享鎖
TX的鎖定模式為表示行級排他鎖這與DML的效果一致
for update操作commit後
當commit後就會發現鎖已被釋放
for update與update互鎖問題
) session 中
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>select * from test for update;
A B
) session 中
update>aaa@AAAUSORACLECOM>update test set a= where a=
此時這條語句處於阻塞狀態說明等待鎖
查看鎖
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
DCCC DCDC TX
AB ABC TM
AB ABA TM
AF AF TX
發現有兩個會話處於有鎖的活動
發出for update操作的session (sid=)的有模式為(row share)的行級共享意向表級鎖模式為(exclusive)行級排他鎖
發出update操作的session (sid=)的模式為(row exclusive)的行級排他意向鎖模式為(None)的行級鎖
這說明第二個session(sid=)由於是後發出的操作它會首先去檢索將要操作的表是否存在鎖此處由於存在故就堵塞了所以沒有獲得行級鎖
這也就說兩個session在檢測操作對象是否處於被鎖狀態時是首先檢測其表級鎖這就避免了去檢測沒一行的鎖這就提升了性能
像這裡的情況我們所操作的對象是行但所利用的檢測鎖機制是在表級
同時會發現session (sid=)的TX鎖的BLOCK為這表示此鎖堵住了另外的鎖同時我們會看到session (sid=)的TX鎖等待的對象ID和ID與sid=的相同這說明sid=的堵住了sid=的
rollback第一個會話的for update操作
rollback>aaa@AAAUSORACLECOM>rollback
回退已完成
查看鎖
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
AB ABC TM
AEB AEBC TX
可見第一鎖的信息已沒有
此時只有session 的鎖的信息而且session 已獲得鎖
如果再將session 進行回滾就會發現session 的鎖也沒有了
實體完整性引發的鎖阻塞
在具有primary key約束的表中在兩個session中插入同樣的記錄
alter>aaa@AAAUSORACLECOM>alter table test add constraint pk_a primary key(a)
表已更改
Session 中
insert>aaa@AAAUSORACLECOM>insert into test(a) values()
已創建 行
Session 中
insert>aaa@AAAUSORACLECOM>insert into test(a) values()
session 處於阻塞狀態
可見在session沒有提交的情況實體完整性約束就會阻塞住session
查看鎖
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select * from v$lock;
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
DCCC DCDC TX
AEB AEBC TX
AB ABC TM
AB ABA TM
AEC AEA TX
可見session (sid=)已獲得TM和TX鎖並且阻塞住了其它的鎖
session (sid=)被阻塞
可以發現 session 已獲得了行排他鎖
AEB AEBC TX
已經完全分配了新的事務所以session 不是被堵在和session 競爭同一個數據塊上(如上面的例子)而是被堵在了完整行約束上
DCCC DCDC TX
這個鎖請求的類型為 (share)
Sessio
rollback>aaa@AAAUSORACLECOM>rollback
回退已完成
Session
insert>aaa@AAAUSORACLECOM>insert into test(a) values()
已創建 行
cellPadding= width=% bgColor=#cccccc>
ff>
ADDR KADDR SID TYPE ID D LMODE REQUEST CTIME BLOCK
AB ABC TM
AEB AEBC TX
可見session 所持有的鎖剩余兩個那個原來等待session 的鎖已釋放
參照完整性引發的鎖阻塞
create>aaa@AAAUSORACLECOM>create table test_child(c numbera number not null constra
int pk_a_ref references test(a))
表已創建
insert>aaa@AAAUSORACLECOM>insert into test(a) values()
已創建 行
Session
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlockedobj
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT
XIDSQN
AAA Row Exclusive TEST
AAA Row share TEST_CHILD
可以發現有兩個對象被鎖住 TEST和TEST_CHILD
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlocks
SID TYPE ID ID LOCK_TYPE REQUEST CTIME
BLOCK
TM Row Exclusive
TM Row share
TX Exclusive
可見有三個鎖
cellPadding= width=% bgColor=#cccccc>
ff>
SQL> select object_name from dba_objects where object_id=;
OBJECT_NAME
TEST
SQL> select object_name from dba_objects where object_id=;
OBJECT_NAME
TEST_CHILD
可見除了TEST表需要的TM和TX鎖外
還同時將TEST_CHILD表鎖住了其鎖類型為Row share
session
insert>aaa@AAAUSORACLECOM>insert into test_child(ca) values()
插入外鍵值為的語句的執行會停頓
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlockedobj
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT
XIDSQN
AAA Row share TEST
AAA Row Exclusive TEST_CHILD
AAA Row Exclusive TEST
AAA Row share TEST_CHILD
這時會發現被鎖住的對象有個這是因為在子表中的插入同時會鎖住父表和子表
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlocks
SID TYPE ID ID LOCK_TYPE REQUEST CTIME
BLOCK
TX None
TM Row share
TM Row Exclusive
TX Exclusive
TM Row Exclusive
TX Exclusive
TM Row share
已選擇行
分析鎖的情況
Session (sid=)有四個鎖分別是子表的TM和TX鎖
TM Row Exclusive
TX Exclusive
父表的TM和TX鎖
TX None
TM Row share
這是因為參照完整性需要父表在參照的過程中不能發生改變所以要對父表加上這些限制
Session
rollback>aaa@AAAUSORACLECOM>rollback
回退已完成
Session
insert>aaa@AAAUSORACLECOM>insert into test_child(ca) values()
insert into test_child(ca) values()
*
ERROR 位於第 行
ORA 違反完整約束條件 (AAAPK_A_REF) 未找到父項關鍵字
更新子表時
update>aaa@AAAUSORACLECOM>update test_child set a= where =
已更新行
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlockedobj
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT
XIDSQN
AAA Row share TEST
AAA Row Exclusive TEST_CHILD
aaa@AAAUSORACLECOM>@showlocks
SID TYPE ID ID LOCK_TYPE REQUEST CTIME
BLOCK
TM Row share
TM Row Exclusive
可見當更新子表時會鎖住父子兩個表即使實際上沒有更新數據
當更新父表時
update>aaa@AAAUSORACLECOM>update test set a= where =
已更新行
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlockedobj
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT
XIDSQN
AAA Row Exclusive TEST
aaa@AAAUSORACLECOM>@showlocks
SID TYPE ID ID LOCK_TYPE REQUEST CTIME
BLOCK
TM Row Exclusive
>
可見更新父表只會鎖住父表
當父子兩個表同時更新時
session
update>aaa@AAAUSORACLECOM>update test_child set a= where =
已更新行
Session
update>aaa@AAAUSORACLECOM>update test set a= where =
session 會被鎖住
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlockedobj
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT
XIDSQN
AAA Row Exclusive TEST
AAA None TEST_CHILD
AAA Row Exclusive TEST
AAA Row Exclusive TEST_CHILD
aaa@AAAUSORACLECOM>@showlocks
SID TYPE ID ID LOCK_TYPE REQUEST CTIME
BLOCK
TM Row Exclusive
TM None
TM Row Exclusive
TM Row Exclusive
可見會發生死鎖是由於第二個session 申請子表的share鎖時發生的
對外鍵建立索引
create>aaa@AAAUSORACLECOM>create index idx_child on test_child(a)
索引已創建
當父子兩個表同時更新時
session
update>aaa@AAAUSORACLECOM>update test_child set a= where =
已更新行
Session
update>aaa@AAAUSORACLECOM>update test set a= where =
已更新行
可見不會發生死鎖
cellPadding= width=% bgColor=#cccccc>
ff>
aaa@AAAUSORACLECOM>@showlockedobj
O_NAME SID LOCK_TYPE OBJECT_NAME XIDUSN XIDSLOT
XIDSQN
AAA Row Exclusive TEST
AAA Row share TEST_CHILD
AAA Row share TEST
AAA Row Exclusive TEST_CHILD
aaa@AAAUSORACLECOM>@showlocks
SID TYPE ID ID LOCK_TYPE REQUEST CTIME
BLOCK
TM Row Exclusive
TM Row share
TM Row share
TM Row Exclusive
可以發現session 獲得TEST_CHILD行級排他意向表鎖同時獲得TEST表的行級共享排他意向鎖
session 獲得TEST行級排他意向表鎖同時獲得TEST_CHILD表的行級共享排他意向鎖
與上個例子相比區別在於前面的例子中session 獲得TEST_CHILD和TEST行級排他意向表鎖
也就是說對外鍵建立索引可以防止兩個表的死鎖
總結
Oracle通過具有意向鎖的多粒度封鎖機制進行並發控制保證數據的一致性其DML鎖(數據鎖)分為兩個層次(粒度)即表級和行級通常的DML操作在表級獲得的只是意向鎖(RS或RX)其真正的封鎖粒度還是在行級另外在Oracle數據庫中單純地讀數據(SELECT)並不加鎖這些都極大地提高了系統的並發程度
在支持高並發度的同時Oracle利用意向鎖及數據行上加鎖標志位等設計技巧減小了Oracle維護行級鎖的開銷使其在數據庫並發控制方面有著明顯的優勢
From:http://tw.wingwit.com/Article/program/Oracle/201311/18429.html