鎖的三種問題(髒讀,幻讀,丟失)

1、簡介

  經過鎖機制能夠實現事務的隔離性要求,使得事務能夠併發地工做。鎖提升了併發,可是卻帶來了問題。不過好在由於事務隔離性的要求,鎖只會帶來三種問題,若是能夠防止這三種狀況的發生,那將不會產生併發異常。算法

2、髒讀

  頁和髒數據的區別:髒頁是指在緩衝池中已經被修改的頁,可是尚未刷新到磁盤中,即數據庫實例內存中的頁和磁盤中的頁的數據不一致,固然在刷新到磁盤以前,日誌都已近被寫入到重作日誌文件中。髒數據是指事務對緩衝池中行記錄的修改,而且尚未被提交(commit)。數據庫

  髒頁是由於數據庫實例內存和磁盤的異步形成的,這並不影響數據的一致性(或者說二者最終會達到一致性,即當髒頁都刷回到磁盤中)。而且由於髒頁的刷新是異步的,不影響數據庫的可用性,所以能夠帶來性能的提升。markdown

  髒數據則不一樣,若是讀到了髒數據,即一個事務能夠讀到另外一個事務中未提交的數據,則顯然違反了數據庫的隔離性。併發

  髒讀指的就是在不一樣的事務下,當前事務能夠讀到另外事務未提交的數據異步

  以下顯示了一個髒讀的例子:性能

  

  上述例子中可發現,在會話A中,在事務沒有提交的前提下,會話B中的兩次SELECT操做取得了不一樣的結果,而且2這條記錄是在會話A中並未提交的數據,即產生了髒讀,違反了事務的隔離性spa

  髒讀現象在生產環境中並不常發生,髒讀發生的條件是須要事務的隔離級別爲READ UNCOMMITTED。InnoDB爲READ REPEATABLE,SQL server爲READ COMMITTED,Oracle爲READ COMMITTED日誌

3、幻讀(不可重複讀)

  不可重複讀是指在一個事務內屢次讀取同一數據集合。在這個事務還沒結束時,另一個事務也訪問該同一數據集合,並作了一些DML操做。所以,在第一個事務中的兩次讀數據之間,因爲第二個事務的修改,那麼第一個事務兩次讀到的數據可能不一致。這樣就發生了在一個事務內兩次讀到的數據不同,這種狀況稱爲不可重複讀。code

  不可重複度和髒讀的區別是:髒讀讀到未提交的數據,而不可重複讀讀到的是已經提交的數據,但其違反了數據庫事務一致性。以下例子:orm

 

 

  通常來講,不可重複讀的問題是能夠接受的,由於讀到是已經提交的數據。

  InnoDB中,經過使用Next-Key Lock算法來避免不可重複讀的問題。在這種算法下,對於索引的掃描,不只是鎖住掃描到的索引,並且還鎖住這些索引覆蓋的範圍(gap)。所以這個範圍內的插入都是不容許的,這樣來避免不可重複讀的現象。

4、丟失更新 

  丟失更新是另外一個鎖致使的問題,就是一個事務的更新操做會被另外一個事務的更新操做鎖覆蓋,從而致使數據的不一致。例如:

  1)事務T1將行記錄R更新爲V1,事務T1並未提交。

  2)同時,事務T2將行記錄R更新爲V2,事務T2未提交。

  3)T1提交

  4)T2提交

  在當前數據庫的任何隔離級別下,都不會致使數據庫理論上的丟失更新問題。這是由於,即便是READ UNCOMMITTED的事務隔離級別,對於行的DML操做,須要對行或者其餘粗粒度級別的對象加鎖。所以在上述2)步驟中,事務T2並不會對行記錄R進行更新操做,由於其會阻塞,直至事務T1提交。

  雖然數據庫能阻止丟失更新問題,但在生產應用中確有邏輯意義上的丟失更新問題,而致使問題的並非由於數據庫自己的問題。以下狀況就會發生丟失更新:

  1)事務T1查詢一行數據,放入本地內存,並顯示給一個終端用戶User1

  2)事務T2也查詢該行數據,並將取得的數據顯示給用戶User2

  3)User1修改這行記錄,更新數據庫並未提交。

  4)User2修改這行記錄,更新數據庫並未提交。

  要避免丟失更新發生,須要讓事務在這種狀況下的操做變成串行化,而不是並行的操做。即在1)中,對用戶讀取的記錄加上排它鎖X。一樣,在2)中,也加上一個排它鎖X。經過這種方式,2)就必須等待1)和3)完成,最後完成4)。如圖:

  

相關文章
相關標籤/搜索