ORACLE的工作機制-5

junsansi發表於2007-08-09

ORACLE的工作機制-5 (by xyf_tck)

下面來講一下ORACLE鎖的機制,分鎖存器和鎖兩種。鎖存器是用來保護對記憶體結構的訪問,比如對DB BUFFER中塊的鎖存器申請,只有在DBWN完成後,這些DB BUFFER塊被解鎖。然後用於其它的申請。鎖存器不可以在程式間共享,鎖存器的申請要麼成功要麼失敗,沒有鎖存器申請佇列。主要的鎖存器有SHARED POOL鎖存器,LIBRARY CACHE鎖存器,CACHE BUFFERS LRU CHAIN鎖存器,CACHE BUFFERS CHAINS鎖存器,REDO ALLOCATION鎖存器,REDO COPY鎖存器。ORACLE的鎖是用來保護資料訪問的,鎖的限制比鎖存器要更寬鬆,比如,多個使用者在修改同一表的不同行時,可以共享一個表上的一個鎖,鎖的申請可以按照被申請的順序來排隊等候,然後依次應用,這種排隊機制叫做佇列(ENPUEUE),如果兩個伺服器程式試圖對同一表的同一行進行加鎖,則都進入鎖的申請佇列,先進的加鎖成功,後面的程式要等待,直到前一個程式解鎖才可以加鎖,這叫做鎖的爭用,而且一旦加鎖成功,這個鎖將一直保持到使用者發出COMMIT或ROOLBACK命令為止。如果兩個使用者鎖定各自的一行並請求對方鎖定的行的時候將發生無限期等待即死鎖,死鎖的發生都是由於鎖的爭用而不是鎖存器的爭用引起的,ORACLE在遇到死鎖時,自動釋放其中一個使用者的鎖並回滾此使用者的改變。正常情況下發生鎖的爭用時,資料的最終儲存結果由SCN來決定哪個程式的更改被最終儲存。兩個使用者的伺服器程式在申請同一表的多個行的鎖的時候是可以交錯進入鎖的申請佇列的。只有其中發生爭用才會進行等待。建立表時指定的MAXTRANS引數決定了表中的一個資料塊同時最多可以被幾個事務鎖定。

下面來講一下ORACLE的讀一致性機制,ORACLE的讀一致性保證了事務之間的高度隔離性。

下面是幾個關於回滾段讀一致性和死鎖的事例:

有表:Test (id number(10)) 有記錄1000000條

SQL> create table test (idnumber(10))tablespaceusers;

表已建立。

SQL> begin

2 foriin 1..1000000 loop

3 insertinto test values(i);

4 endloop;

5 commit;

6 end;

7 /

PL/SQL過程已成功完成

一,大SELECT,小UPDATE

A會話----Select * from test;----設scn=101----執行時間09:10:11

B會話-----Update test set id=9999999 where id=1000000----設scn=102-----執行時間09:10:12

我們會發現B會話會在A會話前完成,A會話中顯示的ID=100000是從回滾段中讀取的,因為A會話在讀到ID=1000000所在的BLOCK時發現BLOCK上有事務資訊,因此要從回滾段中讀,如果UPDATE在SELECT讀到此BLOCK之前已經COMMIT,則SELECT讀到此BLOCK時發現其BLOCK上沒有事務資訊,但是會發現其BLICK的SCN比SELECT自己的SCN大,因此也會利用回滾段進行重構。根據當前塊上所有的itl找到相應的undo地址,重構出之前的block image,之前的那個block又含有自己的itl資訊.如果這個before image中對應的scn不滿足查詢,又會根據undo生成beforebeforeimage,這樣不斷往復,直到構造出符合查詢的scn的block返回結果,或者系統實在無法根據undo構造出符合查詢的block,,報ora-01555的錯誤為止....。需要強調的是讀一致性是通過對當前整個塊利用回滾段(當前塊上的所有ITL記錄的所有回滾段地址)進行遞迴重構到過去某一時間點或某一SCN的塊的一致性快照。而不是隻針對塊中一部分ITL記錄在回滾段中遞迴查詢來完成的,一定要理解遞迴重構與遞迴查詢是完全不同的兩個概念。Oracle回滾段確保了事務的高度的隔離性。即只要回滾段足夠大,那麼一個SELECT不管執行多長,它讀取的所有資料都將是在這條SELECT語句開始執行瞬間這個時間點的值,而不會被其它使用者在SELECT讀取期間對資料是否做過修改而影響。

二、大UPDATE,小SELECT

A會話----Update test set id=1;----設scn=101----執行時間09:10:11

B會話-----select * from test where id=1000000----設scn=102-----執行時間09:10:12

我們會發現B會話會在A會話前完成,B會話中顯示的ID=1000000是從BLOCK中直接讀取的,因為B會話在讀到ID=1000000所在的BLOCK時,A會話還沒有來得及對其鎖定,因此B會話既不會發現BLOCK上有事務資訊,也不會發現BLOCK上的SCN比SELECT的大,因此會從BLOCK中直接讀取,如果SELECT在UPDATE鎖定此BLOCK後才發出,B會話讀到此BLOCK時發現其BLOCK上有事務資訊,因此會從回滾段中讀取。

三、大UPDATE,小UPDATE

A會話----Update test set id=1;----設scn=101----執行時間09:10:11

B會話1-----Update test set id=999999 where id=1000000----設scn=102-----執行時間09:10:12

B會話2----- select * from test where id=2----設scn=103-----執行時間09:10:14

B會話3----- update test set id=3 where id=2----設scn=104-----執行時間09:10:15

我們會發現B會話1會完成,A會話將一直等待,因為B會話1會先於A會話鎖定ID=1000000所在的BLOCK,並改寫頭部的事務資訊,A會話在試圖鎖定此BLOCK時,發現其上有事務資訊,將會一直等待B會話1事務結束後再行鎖定,B會話2查詢到的ID=2是從回滾段中讀取的而不是從BLOCK中直接讀出來的。因為A會話已將ID=2的BLOCK鎖定,並寫入了回滾段,從B會話3可以證明這一點,B會話3發出後,B會話3會收到死鎖的資訊,死鎖的原因是A會話在等待B會話對ID=1000000所在的BLOCK解鎖,現在B會話又在等待A會話對ID=2所在的BLOCK解鎖,因此形成死鎖,因此證明ID=2所在的BLOCK已被A會話鎖定,然後A會話也會收到死鎖的資訊


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

相關文章