天天看點

《Oracle資料庫管理與維護實戰》——2.9 鎖

本節書摘來自異步社群出版社《oracle資料庫管理與維護實戰》一書中的第2章,第2.9節,作者: 何偉娜 , 常建功,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

oracle資料庫管理與維護實戰

為阻止并發事務對資料的一緻性破壞,oracle在系統中鎖定不同的資料庫資源。資料庫鎖防止影響另外一些人使用資料庫。

鎖可分為自動鎖和顯示鎖,當進行資料庫操作時,預設情況下,一個事務會自動獲得所有資料庫資源所需要的鎖。例如,假設開始一項新事務,要更新一個客戶的位址,在更新需要的記錄行之前,oracle進行檢查,确定有沒有其他事務鎖定這行記錄。如果有其他事務鎖定這條記錄,oracle則等待,直到其他事務釋放了該記錄的鎖;如果沒有其他記錄鎖定該記錄,則自動為該記錄上鎖,到該事務送出或復原這個事務時才釋放該鎖。

oracle的預設鎖機制對大多數應用而言已經足夠。但也有一些情況下,事務需要顯示的鎖定資料庫操作需要用到的資料。例如,如果要對表中大多數記錄行進行更新,而表又很大,那麼對整個表鎖定比對一行記錄鎖定更有效。而且,對表進行鎖定可以保證對表更新一次完成,中間不需要有鎖等待。

oracle的鎖根據對象的級别可以分為表級鎖、行級鎖等。

通常,oracle有兩種鎖鎖定資料資源:共享鎖和排他鎖。圖2-30顯示了共享鎖和排他鎖的使用。

1.共享鎖

資料庫資源的共享鎖給予一個事務對特定鎖資源的共享通路,同時另一事務也可以獲得同一資源的共享鎖。例如圖2-30中,兩個事務都具有同一表的共享鎖,這就允許不同僚務在同一時間更新同一表中不同的記錄行。

共享鎖允許事務高度并發性,又稱共享鎖為寫鎖。然而,事務不能總是為所有類型的資源與操作獲得共享鎖。例如,圖2-30中雖然每個事務都可以同時獲得同一個表的共享鎖,但該事務對它所更新的行獲得排他鎖,使其他事務不能更新相同的行,以保護資料安全。

《Oracle資料庫管理與維護實戰》——2.9 鎖

2.排他鎖

排他鎖不同于共享鎖的是,排他鎖在鎖定了某資源後,不允許其他事務擷取該資源,例如圖2-30中,事務1獲得第1行與第2行的排他鎖後,另一事務2不可以在事務1送出或復原前獲得相同行的共享鎖或排他鎖。

排他鎖顯然比共享鎖更嚴格,排他鎖又叫寫鎖,并發性程度更低。因而,oracle不自動擷取資料庫資源的排他鎖,除非個别需要使用,如需阻止其他并發事件的破壞性互動。

當事務進行dml操作(insert、update、delete)時,oracle自動獲得資料庫中表與索引的鎖。為提高并發性并且防止破壞資料,在dml執行過程中,oracle可以同時獲得行級鎖和表級鎖。

1.行級鎖

當事務插入、更新、删除行時,該事務自動獲得該特定行的排他鎖。在行級鎖鎖資料行期間,其他事務不可以對該行更新、删除或修改。舉一個例子,當事務中含有以下語句時,oracle将自動鎖定customers表中的行。

如果其他事務在以上事務送出或復原之前,想更新customers表中的larry ellison的記錄,oracle發現該行已被鎖定,就會讓後來的事務處于等待狀态。

在更新記錄之前,事務可以使用select…for update語句先行鎖定要更新的記錄。例如,以下語句将所有的zipcode為95000的記錄鎖定。

當執行以上語句時,如果不能鎖定所有滿足條件的記錄,oracle會傳回控制。如果沒有nowait關鍵字,select…for update語句就會一直處于等待狀态,直到獲得所有的記錄行。

2.表級鎖

當事務獲得一條記錄上的鎖時,事務自動獲得含該行的表的鎖。當事務更新表中一行或多行時,可以使用表級鎖,以防止其他ddl操作破壞表更新。

例如,要更新customers表中的一行時,事務獲得更新行的排他鎖,同時也獲得customers的表級鎖,将表鎖定以防止其他事務修改或删除表。

事務可以在事務進行過程中獲得表上的共享鎖或排他鎖。當事務執行一條基本的dml操作,如insert、update或delete時,事務通常給共享鎖,但也可以使用排他鎖。這時需要用lock table在表中顯示的指定。例如以下語句就用lock table語句獲得customers的排他鎖。

如果oracle不能立即獲得所需要的表級鎖,nowait會将控制傳回,告知不能立即獲得表級鎖。如果沒有nowait,事務将一直處于等待狀态,直到獲得表級鎖。

oracle實際上還有幾種不同級别的表級鎖,這裡不再詳細介紹,包括行共享、行排他、共享行排他以及排他級别,每個表級鎖都比前一個嚴格。

3.死鎖

死鎖是oracle系統應當盡量避免的情形,它是因為資源共享而引起的。産生的原因是兩個或多個事務等待需要的某個資源,而又不釋放現有的資源。圖2-31示意的是死鎖發生的 過程。

《Oracle資料庫管理與維護實戰》——2.9 鎖

圖2-31中,事務1在表的row #1有一個排他鎖并等待事務2釋放#2的排他鎖,但同時#2具有#1需要的排他鎖并且在等待#1釋放鎖。因而兩個事務一直僵持,如果沒有外來幹預,兩個事務将永遠僵持下去。

死鎖的發生是因為不合理的設計。例如,以下兩個事務,每個事務含有對parts表的多個更新,結果處于死鎖狀态,因為它們各自鎖定了另一個事務需要的行,如表2-7所示。

《Oracle資料庫管理與維護實戰》——2.9 鎖

上述事務的設計容易引起死鎖,當事務1和事務2同時執行時,事務1需要鎖定id=2的行,而事務2将id=2的行已先行鎖定,事務1隻能等待事務2釋放鎖;而事務2又在等待事務1的鎖,兩個事務進入死循環。我們可以對表2-7加以改進,避免死鎖,如表2-8所示。

《Oracle資料庫管理與維護實戰》——2.9 鎖

上述表對事務設計進行了改進,在每一個update語句後面都加commit語句,以及時送出并釋放行級鎖,這樣避免了死鎖。oracle在運作過程中會自動檢測死鎖,并復原産生死鎖的語句以消除死鎖。

前面解釋了oracle自動用于保護dml操作的鎖。但在使用create、alter與drop語句時,oracle也會自動鎖定資料。每個ddl操作在它自己的事務中完成,隻有在進行ddl操作期間才會使用ddl鎖。

1.排他ddl鎖

建立、修改或删除資料庫對象的ddl語句需要對目标對象使用排他鎖。例如,當執行一個alter table語句時,要給表増加完整性限制,事務會自動給表加排他鎖。在alter語句前,其他使用者不能修改或删除該表。

2.共享ddl鎖

一些ddl語句可以獲得資料庫對象的共享ddl鎖,在資料庫對象之間建立互相依賴關系的ddl語句通常需要共享ddl鎖。例如,建立包時,包的過程與函數引用許多不同的資料庫表:當建立這個包時,事務獲得這個包上的排他ddl鎖,同時獲得所引用鎖的共享ddl鎖,這個共享ddl鎖阻止另一個事務獲得所引用表的排他鎖,而且防止oracle在完成包編譯前修改或删除包所引用的表。和dml共享鎖一樣,ddl共享鎖不妨礙另一個事務獲得同一表的共享ddl鎖。