並行事務隔離機制

當多個用戶訪問同一數據庫時會發生的現象介紹如下:

在單用戶環境中,每個事務都是順序執行的,而不會遇到與其他事務的衝突。但是,在多用戶環境下,多個事務可以(而且常常)同時執行。因此每個事務都有可能與其他正在運行的事務發生衝突。有可能與其他事務發生衝突的事務稱爲交錯的 或並行的 事務,而相互隔離的事務稱爲串行化 事務,這意味着同時運行它們的結果與一個接一個連續地運行它們的結果沒有區別。在多用戶環境下,在使用並行事務時,會發生四種現象:

  • 丟失更新:這種情況發生在兩個事務讀取並嘗試更新同一數據時,其中一個更新會丟失。例如:事務 1 和事務 2 讀取同一行數據,並都根據所讀取的數據計算出該行的新值。如果事務 1 用它的新值更新該行以後,事務 2 又更新了同一行,則事務 1 所執行的更新操作就丟失了。由於設計 DB2 的方法,DB2 不允許發生此類現象。
  • 髒讀:當事務讀取尚未提交的數據時,就會發生這種情況。例如:事務 1 更改了一行數據,而事務 2 在事務 1 提交更改之前讀取了已更改的行。如果事務 1 回滾該更改,則事務 2 就會讀取被認爲是不曾存在的數據。
  • 不可重複的讀:當一個事務兩次讀取同一行數據,但每次獲得不同的數據值時,就會發生這種情況。例如:事務 1 讀取了一行數據,而事務 2 在更改或刪除該行後提交了更改。當事務 1 嘗試再次讀取該行時,它會檢索到不同的數據值(如果該行已經被更新的話),或發現該行不復存在了(如果該行被刪除的話)。
  • 幻像:當最初沒有看到某個與搜索條件匹配的數據行,而在稍後的讀操作中又看到該行時,就會發生這種情況。例如:事務 1 讀取滿足某個搜索條件的一組數據行,而事務 2 插入了與事務 1 的搜索條件匹配的新行。如果事務 1 再次執行產生原先行集的查詢,就會檢索到不同的行集。

維護數據庫的一致性和數據完整性,同時又允許多個應用程序同時訪問同一數據,這樣的特性稱爲併發性。 DB2 數據庫用來嘗試強制實施併發性的方法之一是通過使用隔離級別——通過‘事務、隔離級別、鎖’機制,它決定在第一個事務訪問數據時,如何對其他事務鎖定或隔離該事務所使用的數據。 DB2 使用下列隔離級別來強制實施併發性:

  • 可重複的讀(Repeatable Read)
  • 讀穩定性(Read Stability)
  • 遊標穩定性(Cursor Stability)
  • 未提交的讀(Uncommitted Read)

可重複的讀隔離級別可以防止所有現象,但是會大大降低併發性的程度(可以同時訪問同一資源的事務數量)。未提交的讀隔離級別提供了最大的併發性,但是後三種現象都可能出現。

DB2 UDB 支持以下隔離級別:可重複讀(Repeatable read,RR)、讀穩定性(Read stability,RS)、遊標穩定性(Cursor stability,CS)、未提交讀(Uncommitted read,UR),下面分別講述:

 

可重複讀(Repeatable read,RR) 確保 工作單元(UOW)期間的任何錶行讀操作直到 UOW 完成,
不會被其他應用程序進程更改。類似地,由另一個應用程序進程更改的任何行直到由該應用程序進程提交,不會被讀取。
運行在 RR 級別的應用程序進程是完全與併發應用程序進程的效果相隔離的。

 

RR 隔離級別通常會直接對錶加 S 鎖,所以對併發的影響最大,但有一種情況例外:如果 WHERE 條件字段上建有主鍵或者 UNIQUE INDEX,並且通過主鍵或者 UNIQUE INDEX 進行查詢,那麼數據庫將只對表加 IS 鎖,結果行加 S 鎖——在鎖列表足夠用,沒有發生鎖升級的情況下才成立,也就是說,這個時候 RR 級別 =RS 級別,這時不允許其他事務對這些行進行更新或者刪除,因爲對行的更新或者刪除會對相應的行加 X 鎖,這和行 S 鎖相排斥;其他情況下,會直接對錶加 S 鎖,這時將不允許其他事務對任何行進行更新或者刪除。

 

 

讀穩定性(Read stability,RS)類似於 RR 。但是,運行在 RS 級別的應用程序進程不是完全與併發應用程序
進程的效果相隔離的。如果這樣的應用程序進程不止一次發出同樣的查詢,它就會看到更改了的數據或者由其他
應用程序進程添加的新的“幻影(phantom)”行。

RS 隔離級別會對錶加 IS 鎖,結果行加 NS 鎖,這時不允許其他事務對這些行進行更新(UPDATE/DELETE),但是允許插入任何行,因爲對這些行的更新會對相應的行加 X 鎖,這和行 NS 鎖相排斥——上述說法基於鎖列表足夠用,沒有發生鎖升級的情況下才成立。

 

遊標穩定性(Cursor stability,CS)也確保由另一個應用程序進程更改的任何行直到被那個應用程序進程提交,
不會被讀取。 CS 隔離級別只確保每個可更新遊標當前行不被其他應用程序進程更改;
在 UOW 期間讀過的行可以被其他應用程序進程更改。針對可滾動更新遊標,在提交之前,會對所有結果行一直加 U 鎖,
無論遊標滾動到什麼地方; CS 隔離級別針對不可更新遊標會對錶加 IS 鎖,如果未在 WHERE 條件字段上創建索引,
查詢首先會查找鎖列表,檢查鎖列表中是否存在與 IS 鎖相排斥的鎖,如果存在的話,
那麼將等待所有持有排斥鎖的事務提交,查詢才能執行下去;如果 WHERE 條件字段創建了索引,並且使用了索引,
那麼查詢將通過索引得到結果行,然後檢查鎖列表中是否存在與結果行相排斥的鎖,如果存在的話,
那麼將等待所有持有排斥鎖的事務提交,查詢才能執行下去 .
未提交讀(Uncommitted read,UR)對於某些操作,允許在 UOW 期間讀過的任何行可以被其他應用程序進程
更改,並允許讀任何被另一個應用程序進程更改過的行,即使該更改還沒有提交。對於其他操作,UR 類似於 CS 。

綜上所述,離級別對併發性具有最顯著的影響,不同隔離級別獲得的資源的鎖定範圍也不同,如果所有事務都能做到不過分貪婪的佔有鎖資源——鎖的範圍大、佔用時間長,那麼事務之間發生鎖衝突的可能性將大大降低,事務的併發性也將會很好。那麼如何選擇正確的隔離級別呢?

使用的隔離級別不僅影響數據庫對併發性的支持如何,而且影響併發應用程序的性能。通常,使用的隔離級別越嚴格,併發性就越小,某些應用程序的性能可能會越低,因爲它們要等待資源上的鎖被釋放。那麼,如何決定要使用哪種隔離級別呢?最好的方法是確定哪些現象是不可接受的,然後選擇能夠防止這些現象發生的隔離級別:

  • 如果正在執行大型查詢,而且不希望併發事務所做的修改導致查詢的多次運行返回不同的結果,則使用可重複的讀隔離級別。
  • 如果希望在應用程序之間獲得一定的併發性,還希望限定的行在事務執行期間保持穩定,則使用讀穩定性隔離級別。
  • 如果希望獲得最大的併發性,同時不希望查詢看到未提交的數據,則使用遊標穩定性隔離級別。
  • 如果正在只讀的表 / 視圖 / 數據庫上執行查詢,或者並不介意查詢是否返回未提交的數據,則使用未提交的讀隔離級別。 對於統計類報表,不需要得到十分精確的數據,那麼最好使用 UR 隔離級別,既可以節省昂貴的鎖列表資源,也不會因爲鎖衝突影響其他事務的執行,同時也不會受到其他事務的影響,順利的得到統計結果。未提交的讀隔離級別通常用於那些訪問只讀表和視圖的事務,以及某些執行 SELECT 語句的事務(只要其他事務的未提交數據對這些語句沒有負面效果)。 顧名思義,其他事務對行所做的更改在已經提交之前對於使用未提交的讀隔離級別的事務是可見的。但是,此類事務不能看見或訪問其他事務所創建的表、視圖或索引,直到那些事務被提交爲止。類似地,如果其他事務刪除了現有的表、視圖或索引,那麼僅當進行刪除操作的事務終止時,使用未提交的讀隔離級別的事務才能知道這些對象不再存在了。(一定要注意一點:當運行在未提交的讀隔離級別下的事務使用可更新遊標時,該事務的行爲和在遊標穩定性隔離級別下運行一樣,並應用遊標穩定性隔離級別的約束。)

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章