轉載--oracle DML鎖

wadekobe9發表於2012-02-16

Oracle多粒度封鎖機制研究

1       引言—資料庫鎖的基本概念

為了確保併發使用者在存取同一資料庫物件時的正確性(即無丟失修改、可重複讀、不讀“髒”資料),資料庫中引入了鎖機制。基本的鎖型別有兩種:排它鎖(Exclusive locks記為X鎖)和共享鎖(Share locks記為S鎖)。

排它鎖:若事務T對資料DX鎖,則其它任何事務都不能再對D加任何型別的鎖,直至T釋放D上的X鎖;一般要求在修改資料前要向該資料加排它鎖,所以排它鎖又稱為寫鎖

共享鎖:若事務T對資料DS鎖,則其它事務只能對DS鎖,而不能加X鎖,直至T釋放D上的S鎖;一般要求在讀取資料前要向該資料加共享鎖,所以共享鎖又稱為讀鎖

2       Oracle 多粒度封鎖機制介紹

根據保護物件的不同,Oracle資料庫鎖可以分為以下幾大類:

(1)      DML lockdata locks,資料鎖):用於保護資料的完整性;

(2)      DDL lockdictionary 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   OracleTX鎖(行級鎖、事務鎖)

許多對Oracle不太瞭解的技術人員可能會以為每一個TX鎖代表一條被封鎖的資料行,其實不然。TX的本義是Transaction(事務),當一個事務第一次執行資料更改(InsertUpdateDelete)或使用SELECT… FOR UPDATE語句進行查詢時,它即獲得一個TX(事務)鎖,直至該事務結束(執行COMMITROLLBACK操作)時,該鎖才被釋放。所以,一個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鎖。

另外,基本的鎖型別(SX)與意向鎖型別(ISIX)之間還可以組合出新的鎖型別,理論上可以組合出4種,即:S+ISS+IXX+ISX+IX,但稍加分析不難看出,實際上只有S+IX有新的意義,其它三種組合都沒有使鎖的強度得到提高(即:S+IS=SX+IS=XX+IX=X,這裡的“=”指鎖的強度相同)。所謂鎖的強度是指對其它鎖的排斥程度。

這樣我們又可以引入一種新的鎖的型別

共享意向排它鎖Shared Intent Exclusive Lock,簡稱SIX鎖) :如果對一個資料庫物件加SIX鎖,表示對它加S鎖,再加IX鎖,即SIX=S+IX。例如:事務對某個表加SIX鎖,則表示該事務要讀整個表(所以要對該表加S鎖),同時會更新個別行(所以要對該表加IX鎖)。

這樣資料庫物件上所加的鎖型別就可能有5種:即SXISIXSIX

具有意向鎖的多粒度封鎖方法中任意事務T要對一個資料庫物件加鎖,必須先對它的上層結點加意向鎖。申請封鎖時應按自上而下的次序進行;釋放封鎖時則應按自下而上的次序進行;具有意向鎖的多粒度封鎖方法提高了系統的併發度,減少了加鎖和解鎖的開銷。

2.2.3   OracleTM鎖(表級鎖)

OracleDML(資料鎖)正是採用了上面提到的多粒度封鎖方法,其行級鎖雖然只有一種(即X鎖),但其TM鎖(表級鎖)型別共有5種,分別稱為共享鎖(S鎖)、排它鎖(X鎖)、行級共享鎖(RS鎖)、行級排它鎖(RX鎖)、共享行級排它鎖(SRX鎖),與上面提到的SXISIXSIX相對應。需要注意的是,由於Oracle在行級只提供X鎖,所以與RS鎖(通過SELECT … FOR UPDATE語句獲得)對應的行級鎖也是X鎖(但是該行資料實際上還沒有被修改),這與理論上的IS鎖是有區別的。

下表為Oracle資料庫TM鎖的相容矩陣(Y=Yes,表示相容的請求; N=No,表示不相容的請求;-表示沒有加鎖請求):

 

 

1 NULL

2 SS

3 SX

4 S

5 SSX

6 X

1 NULL

YES

YES

YES

YES

YES

YES

2 SS(RS)

YES

YES

YES

YES

YES

NO

3 SX(RX)

YES

YES

YES

NO

NO

NO

4 S

YES

YES

NO

YES

NO

NO

5 SSX(SRX)

YES

YES

NO

NO

NO

NO

6 X

YES

NO

NO

NO

NO

NO

 

表一:Oracle資料庫TM鎖的相容矩陣

 

一方面,當Oracle執行SELECT…FOR UPDATEINSERTUPDATEDELETEDML語句時,系統自動在所要操作的表上申請表級RS鎖(SELECT…FOR UPDATE)或RX鎖(INSERTUPDATEDELETE),當表級鎖獲得後,系統再自動申請TX鎖,並將實際鎖定的資料行的鎖標誌位置位(指向該TX鎖);另一方面,程式或操作人員也可以通過LOCK TABLE語句來指定獲得某種型別的TM鎖。下表總結了Oracle中各SQL語句產生TM鎖的情況:

SQL語句

表鎖模式

允許的鎖模式

Select * from table_name……

RSRXSSRXX

Insert into table_name……

RX

RSRX

Update table_name……

RX

RSRX

Delete from table_name……

RX

RSRX

Select * from table_name for update

RS

RSRXSSRX

lock table table_name in row share mode

RS

RSRXSSRX

lock table table_name in row exclusive mode

RX

RSRX

lock table table_name in share mode

S

RSS

lock table table_name in share row exclusive mode

SRX

RS

lock table table_name in exclusive mode

X

表二:Oracle資料庫TM鎖小結

 

我們可以看到,通常的DML操作(SELECT…FOR UPDATEINSERTUPDATEDELETE),在表級獲得的只是意向鎖(RSRX),其真正的封鎖粒度還是在行級;另外,Oracle資料庫的一個顯著特點是,在預設情況下,單純地讀資料(SELECT)並不加鎖,Oracle通過回滾段(Rollback segment)來保證使用者不讀“髒”資料。這些都極大地提高了系統的併發程度。

由於意向鎖及資料行上鎖標誌位的引入,極大地減小了Oracle維護行級鎖的開銷,這些技術的應用使Oracle能夠高效地處理高度併發的事務請求。

 

TM鎖的5級別的解釋

 

0-- none

 

1-- null

 

2--行級共享鎖(Row  Shared,簡稱RS鎖)

通常是通過select …from  for  update語句新增的,同時該方法也是我們用來手工鎖定某

些記錄的主要方法。比如,當我們在查詢某些記錄的過程中,不希望其他使用者對查詢的記

錄進行更新操作,則可以發出這樣的語句。當資料使用完畢以後,直接發出rollback命令

將鎖定解除。當表上新增了RS鎖定以後,不允許其他事務對相同的表新增排他鎖,但是允

許其他的事務通過DML語句或lock命令鎖定相同表裡的其他資料行。

 

3 --行級排他鎖(Row Exclusive,簡稱RX鎖)

Dml Insert Update Delete 

當我們進行DML時會自動在被更新的表上新增RX鎖,或者也可以通過執行lock命令顯式的

在表上新增RX鎖。在該鎖定模式下,允許其他的事務通過DML語句修改相同表裡的其他數

據行,或通過lock命令對相同表新增RX鎖定,但是不允許其他事務對相同的表新增排他鎖(X鎖)。

 

4--共享鎖(Share,簡稱S鎖)

通過lock  table  in  share  mode命令新增該S鎖。在該鎖定模式下,不允許任何使用者更新表。

但是允許其他使用者發出select …from for update命令對錶新增RS鎖。

 

5--共享行級排他鎖(Share Row Exclusive,簡稱SRX鎖)

通過lock  table in  share  row  exclusive mode命令新增SRX鎖。該鎖定模式比行級排他鎖

和共享鎖的級別都要高,這時不能對相同的表進行DML操作,也不能新增共享鎖。

 

6--排他鎖(Exclusive,簡稱X鎖)

通過lock  table  in  exclusive  mode命令新增X鎖。在該鎖定模式下,其他使用者不能對錶進

行任何的DMLDDL操作,該表上只能進行查詢。

 

3       Oracle 多粒度封鎖機制的監控

3.1   系統檢視介紹

為了監控Oracle系統中鎖的狀況,我們需要對幾個系統檢視有所瞭解:

3.1.1   v$lock檢視

v$lock檢視列出當前系統持有的或正在申請的所有鎖的情況,其主要欄位說明如下:

欄位名稱

型別

說明

SID

NUMBER

會話(SESSION)標識;

TYPE

VARCHAR2

區分該鎖保護物件的型別;

ID1

NUMBER

鎖標識1

ID2

NUMBER

鎖標識2

LMODE

NUMBER

鎖模式:0None),1null,2row share, 3row exclusive,4 share,5share row exclusive,6exclusive

REQUEST

NUMBER

申請的鎖模式:具體值同上面的LMODE

CTIME

NUMBER

已持有或等待鎖的時間;

BLOCK

NUMBER

是否阻塞其它鎖申請;

表三:v$lock檢視主要欄位說明

如果某個request列是一個非0值,那麼它就是在等待一個鎖。  如果block列是1,這個SID 就持有了一個鎖,並且阻塞別人獲得這個鎖。  

其中在TYPE欄位的取值中,本文只關心TMTX兩種DML鎖型別;

關於ID1ID2TYPE取值不同其含義也有所不同:

TYPE

ID1

ID2

TM

被修改表的標識(object_id

0

TX

以十進位制數值表示該事務所佔用的回滾段號與該事務在該回滾段的事務表(Transaction table)中所佔用的槽號(slot number,可理解為記錄號)。其組成形式為: 0xRRRRSSSS ( RRRR = RBS number, SSSS = slot )

以十進位制數值表示環繞(wrap)次數,即該槽(slot)被重用的次數;

表四:v$lock檢視中ID1ID2欄位取值說明

3.1.2   v$locked_object檢視

v$locked_object檢視列出當前系統中哪些物件正被鎖定,其主要欄位說明如下:

欄位名稱

型別

說明

XIDUSN

NUMBER

回滾段號;

XIDSLOT

NUMBER

槽號;

XIDSQN

NUMBER

序列號;

OBJECT_ID

NUMBER

被鎖物件標識;

SESSION_ID

NUMBER

持有鎖的會話(SESSION)標識;

ORACLE_USERNAME

VARCHAR230

持有該鎖的使用者的Oracle使用者名稱;

OS_USER_NAME

VARCHAR215

持有該鎖的使用者的作業系統使用者名稱;

PROCESS

VARCHAR29

作業系統的程式號;

LOCKED_MODE

NUMBER

鎖模式,取值同表三中的LMODE

表五:v$locked_object檢視欄位說明

3.2   監控指令碼

根據上述系統檢視,可以編制指令碼來監控資料庫中鎖的狀況。

3.2.1   showlock.sql

第一個指令碼showlock.sql,該指令碼通過連線v$locked_objectall_objects兩檢視,顯示哪些物件被哪些會話鎖住:

 

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,該指令碼主要顯示當前所有TMTX鎖的資訊;

/* 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#1SESS#2表示)以SCOTT使用者連入資料庫,以操作Oracle提供的示例表(DEPTEMP);另一個(以下用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   ID   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#1SID17)在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

分解結果與第一個指令碼直接查出來的XIDUSNXIDSLOT相同,而TX鎖的ID25861)與XIDSQN相同,可見當LOCK TYPETX時,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#1SID17)持有Row share鎖外,又增加了SESS#2SID19)持有的Row Exclusive鎖,但還沒有為SESS#2分配回滾段(XIDUSNXIDSLOTXIDSQN的值均為0);而從第二個指令碼看到,SESS#2TX鎖的LOCK_TYPENone,其申請的鎖型別(REQUEST)為6(即Exclusive),而其ID1ID2的值與SESS#1所持有的TX鎖的ID1ID2相同,SESS#1TX鎖的阻塞域(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鎖也已經獲得,並且ID1ID2是其真正的Transaction ID。再將會話2的事務進行回滾。

SESS#2

SQL> rollback;

Rollback complete.

檢查系統鎖的情況:

SESS#3

SQL> @showlock

no rows selected

SQL> @showalllock

no rows selected

可以看到,TMTX鎖已全部被釋放。

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表中插入一條DEPTNO50的記錄後,SESS#1SID7)在DEPT表上獲得Row Exclusive鎖,並且由於進行了資料插入,該事務被分配了回滾段,獲得TX鎖。

SESS#2

INSERT INTO DEPT(DEPTNO) VALUES(50);

這時,SESS#2SID8)也向DEPT表中插入一條DEPTNO50的記錄,該語句被阻塞,檢查鎖情況:

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#2DEPT表上也獲得了Row Exclusive鎖,同樣也獲得了回滾段的分配,得到TX鎖,但是由於其插入的記錄與SESS#1插入的記錄的DEPTNO均為50,該語句成功與否取決於SESS#1的事務是提交還是回滾,所以SESS#2被阻塞,表現為SESS#2Share方式(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只持有原先已有的TMTX鎖,其等待的TX鎖(由SESS#1持有)也消失了。

如果SESS#1提交而不是回滾,在SESS#2上將會出現如下提示:

ERROR at line 1:

ORA-00001: unique constraint (SCOTT.PK_DEPT) violated錯誤。

即發生主鍵衝突,SESS#1SESS#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#1SID7)在DEPT表中先插入一條DEPTNO60的記錄,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#2SID8)向EMP表中出入一條新記錄,該記錄DEPT值為60(即SESS#1剛插入,但還未提交的記錄的DEPTNO值),SESS#2獲得了EMP表上的Row Exclusive鎖,另外由於插入記錄,還分配了回滾段及一個TX鎖,但由於SESS#2的插入語句是否成功取決於SESS#1的事務是否進行提交,所以它被阻塞,表現為SESS#2ShareREQUEST=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持有的鎖也被全部釋放。

 

 

這裡再插入一種情況進來,當修改子表的時候沒提交,

無法修改父表的參考列的值

會話1

select   Userenv('SID')   From   dual  --508

Delete   From   emp   Where   empno=7369

不提交

 

會話2

select   Userenv('SID')   From   dual  --488

Update   dept   Set   deptno=99   Where   deptno=80

會話阻塞了

 

會話3

select   *   From   v$lock   Where   Sid   In   (508,488)

ADDR      KADDR     SID TYPE  ID1  ID2     LMODE    REQUEST  CTIME  BLOCK

327713DC      327713F4      488    TM     139627 0           3        0        30     0

327714A0      327714B8      488    TM     139629 0           0        4         30     0

318B350C      318B3628      508    TX     655364 99274  6           0         30     0

32771254      3277126C      508    TM     139627 0           2        0         30     0

32771318      32771330      508    TM     139629 0           3        0         30     1

 

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#1SID7)做了一個刪除操作,但由於條件(0=1)為永假,所以實際上並沒有一行被刪除,從監控指令碼可以看出SESS#1EMP表上獲得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#2EMP表上獲得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

可以看到,在EMPDEPTNO列上建立索引後,在DEPT表上執行DELETE操作,不再要求在EMP表上加Share鎖,只是在DEPT表上加Row Exclusive鎖,封鎖的粒度減小,引起阻塞的可能性也減小。

5       Oracle 多粒度封鎖機制總結

Oracle通過具有意向鎖的多粒度封鎖機制進行併發控制,保證資料的一致性。其DML鎖(資料鎖)分為兩個層次(粒度):即表級和行級。通常的DML操作在表級獲得的只是意向鎖(RSRX),其真正的封鎖粒度還是在行級;另外,在Oracle資料庫中,單純地讀資料(SELECT)並不加鎖,這些都極大地提高了系統的併發程度。

在支援高併發度的同時,Oracle利用意向鎖及資料行上加鎖標誌位等設計技巧,減小了Oracle維護行級鎖的開銷,使其在資料庫併發控制方面有著明顯的優勢。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10678398/viewspace-716566/,如需轉載,請註明出處,否則將追究法律責任。

相關文章