全面講解Oracle鎖存器
Oracle有很多值得學(xué)習(xí)的地方,這里我們主要介紹Oracle鎖存器,包括介紹Oracle的讀一致性機制等方面。Oracle鎖的機制,分Oracle鎖存器和鎖兩種。鎖存器是用來保護對內(nèi)存結(jié)構(gòu)的訪問,比如對DB BUFFER中塊的鎖存器申請,只有在DBWN完成后,這些DB BUFFER塊被解鎖。然后用于其它的申請。
Oracle鎖存器不可以在進程間共享,鎖存器的申請要么成功要么失敗,沒有鎖存器申請隊列。主要的Oracle鎖存器有SHARED POOL鎖存器,LIBRARY CACHE鎖存器,CACHE BUFFERS LRU CHAIN鎖存器,CACHE BUFFERS CHAINS鎖存器,REDO ALLOCATION鎖存器,REDO COPY鎖存器。
Oracle的鎖是用來保護數(shù)據(jù)訪問的,鎖的限制比鎖存器要更寬松,比如,多個用戶在修改同一表的不同行時,可以共享一個表上的一個鎖,鎖的申請可以按照被申請的順序來排隊等候,然后依次應(yīng)用,這種排隊機制叫做隊列(ENPUEUE),如果兩個服務(wù)器進程試圖對同一表的同一行進行加鎖,則都進入鎖的申請隊列,先進的加鎖成功,后面的進程要等待,直到前一個進程解鎖才可以加鎖,這叫做鎖的爭用,而且一旦加鎖成功,這個鎖將一直保持到用戶發(fā)出COMMIT或ROOLBACK命令為止。
如果兩個用戶鎖定各自的一行并請求對方鎖定的行的時候?qū)l(fā)生無限期等待即死鎖,死鎖的發(fā)生都是由于鎖的爭用而不是鎖存器的爭用引起的,Oracle在遇到死鎖時,自動釋放其中一個用戶的鎖并回滾此用戶的改變。正常情況下發(fā)生鎖的爭用時,數(shù)據(jù)的最終保存結(jié)果由SCN來決定哪個進程的更改被最終保存。兩個用戶的服務(wù)器進程在申請同一表的多個行的鎖的時候是可以交錯進入鎖的申請隊列的。只有其中發(fā)生爭用才會進行等待。創(chuàng)建表時指定的MAXTRANS參數(shù)決定了表中的一個數(shù)據(jù)塊同時最多可以被幾個事務(wù)鎖定。
下面來講一下Oracle的讀一致性機制,Oracle的讀一致性保證了事務(wù)之間的高度隔離性。下面是幾個關(guān)于回滾段讀一致性和死鎖的事例:
一、大SELECT,小UPDATE
A會話----Select * from test;----設(shè)scn=101----執(zhí)行時間09:10:11
B會話-----Update test set id=9999999 where id=1000000----設(shè)scn=102-----執(zhí)行時間09:10:12
我們會發(fā)現(xiàn)B會話會在A會話前完成,A會話中顯示的ID=100000是從回滾段中讀取的,因為A會話在讀到ID=1000000所在的BLOCK時發(fā)現(xiàn)BLOCK上有事務(wù)信息,因此要從回滾段中讀,如果UPDATE在SELECT讀到此BLOCK之前已經(jīng)COMMIT,則SELECT讀到此BLOCK時發(fā)現(xiàn)其BLOCK上沒有事務(wù)信息,但是會發(fā)現(xiàn)其BLICK的SCN比SELECT自己的SCN大,因此也會利用回滾段進行重構(gòu)。根據(jù)當前塊上所有的itl找到相應(yīng)的undo地址,重構(gòu)出之前的block image,之前的那個block又含有自己的itl信息.如果這個before image中對應(yīng)的scn不滿足查詢,又會根據(jù)undo生成beforebeforeimage,這樣不斷往復(fù),直到構(gòu)造出符合查詢的scn的block返回結(jié)果,或者系統(tǒng)實在無法根據(jù)undo構(gòu)造出符合查詢的block,,報ora-01555的錯誤為止....。需要強調(diào)的是讀一致性是通過對當前整個塊利用回滾段(當前塊上的所有ITL記錄的所有回滾段地址)進行遞歸重構(gòu)到過去某一時間點或某一SCN的塊的一致性快照。而不是只針對塊中一部分ITL記錄在回滾段中遞歸查找來完成的,一定要理解遞歸重構(gòu)與遞歸查找是完全不同的兩個概念。Oracle回滾段確保了事務(wù)的高度的隔離性。即只要回滾段足夠大,那么一個SELECT不管執(zhí)行多長,它讀取的所有數(shù)據(jù)都將是在這條SELECT語句開始執(zhí)行瞬間這個時間點的值,而不會被其它用戶在SELECT讀取期間對數(shù)據(jù)是否做過修改而影響。
二、大UPDATE,小SELECT
A會話----Update test set id=1;----設(shè)scn=101----執(zhí)行時間09:10:11
B會話-----select * from test where id=1000000----設(shè)scn=102-----執(zhí)行時間09:10:12
我們會發(fā)現(xiàn)B會話會在A會話前完成,B會話中顯示的ID=1000000是從BLOCK中直接讀取的,因為B會話在讀到ID=1000000所在的BLOCK時,A會話還沒有來得及對其鎖定,因此B會話既不會發(fā)現(xiàn)BLOCK上有事務(wù)信息,也不會發(fā)現(xiàn)BLOCK上的SCN比SELECT的大,因此會從BLOCK中直接讀取,如果SELECT在UPDATE鎖定此BLOCK后才發(fā)出,B會話讀到此BLOCK時發(fā)現(xiàn)其BLOCK上有事務(wù)信息,因此會從回滾段中讀取。
三、大UPDATE,小UPDATE
A會話----Update test set id=1;----設(shè)scn=101----執(zhí)行時間09:10:11
B會話1-----Update test set id=999999 where id=1000000----設(shè)scn=102-----執(zhí)行時間09:10:12
B會話2----- select * from test where id=2----設(shè)scn=103-----執(zhí)行時間09:10:14
B會話3----- update test set id=3 where id=2----設(shè)scn=104-----執(zhí)行時間09:10:15
我們會發(fā)現(xiàn)B會話1會完成,A會話將一直等待,因為B會話1會先于A會話鎖定ID=1000000所在的BLOCK,并改寫頭部的事務(wù)信息,A會話在試圖鎖定此BLOCK時,發(fā)現(xiàn)其上有事務(wù)信息,將會一直等待B會話1事務(wù)結(jié)束后再行鎖定,B會話2查詢到的ID=2是從回滾段中讀取的而不是從BLOCK中直接讀出來的。因為A會話已將ID=2的BLOCK鎖定,并寫入了回滾段,從B會話3可以證明這一點,B會話3發(fā)出后,B會話3會收到死鎖的信息,死鎖的原因是A會話在等待B會話對ID=1000000所在的BLOCK解鎖,現(xiàn)在B會話又在等待A會話對ID=2所在的BLOCK解鎖,因此形成死鎖,因此證明ID=2所在的BLOCK已被A會話鎖定,然后A會話也會收到死鎖的信息。以上介紹Oracle鎖存器。
【編輯推薦】