髒讀、幻讀、不可重複讀和遺失更新實例

PHP中文网
發布: 2017-06-21 15:55:55
原創
2617 人瀏覽過

2017年6月5日,天氣-下雨。

      前兩天整理之前的學習筆記時,發現對事務並發產生的問題——髒讀、幻讀、不可重複讀和丟失更新這些概念有點模糊,於是又重新溫習了一遍,現在把自己的一些理解歸納整理如下,方便大家學習。

       鎖定是防止其他事務存取指定資源的手段。鎖是實現並發控制的主要方法,也是多個使用者能夠同時操縱同一個資料庫中的資料而不發生資料不一致現象的重要保障。 一般來說,鎖可以防止髒讀、不可重複讀和幻讀。

1.髒讀(Dirty Read)-一個事務讀取到了另外一個事務沒有提交的資料。

詳細解釋:當一個事務正在存取數據並且對數據進行了修改,而這種修改還沒有提交到資料庫中,這時另外一個事務也訪問這個數據,然後使用了這個數據。因為這個數據是還沒有提交的數據,那麼另外一個事務讀到的這個數據是髒數據,而依據髒數據所做的操作可能是不正確的。

事務T1:更新一筆資料
          -->事務T2:讀取事務T1更新的記錄
 事務T1:呼叫commit進行提交
 此時事務T2讀取到的數據是保存在資料庫記憶體中的數據,稱為髒數據,這個過程稱為髒讀。

髒讀發生在一個事務A讀取了被另一個事務B修改,但是還未提交的資料。假如B回退,則事務A讀取的是無效的資料。這跟不可重複讀取類似,但是第二個交易不需要執行提交。

解決髒讀問題:修改時加排他鎖,直到事務提交後才釋放,讀取時加上共享鎖,讀取完釋放事務1讀取資料時加上共享鎖後(這樣在事務1讀取數據的過程中,其他事務就不會修改該數據),不允許任何事務操作該數據,只能讀取,之後1如果有更新操作,那麼會轉換為排他鎖,其他事務更無權參與進來讀寫,這樣就防止了髒讀問題。但是當事務1讀取數據過程中,有可能其他事務也讀取了該數據,讀取完畢後共享鎖釋放,此時事務1修改數據,修改完畢提交事務,其他事務再次讀取數據時候發現數據不一致,就會出現不可重複讀問題,所以這樣不能夠避免不可重複讀問題。

2.幻讀(Phantom-在同一事務中,用同樣的操作讀取兩次,得到的記錄數不相同。

詳細解釋:幻讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好像發生了幻覺一樣。

事務T1:查詢表中所有記錄
          -->事務T2:插入一筆記錄
          -->事務T2:調用commit提交
#T1:再次詢問表格中所有記錄
            
#此時事務T1兩次所詢問的記錄是不一樣的,稱為幻讀。

注意:幻讀重點在新增或刪除。

幻讀發生在當兩個完全相同的查詢執行時,第二次查詢所傳回的結果集合跟第一個查詢不相同。

發生的情況:沒有範圍鎖定。

如何避免:實行序列化隔離模式,在任何一個低層級的隔離中都可能會發生。

解決幻讀問題:採用的是範圍鎖定RangeS RangeS_S模式,鎖定檢索範圍為唯讀,這樣就避免了幻讀問題。

3.不可重複讀取(Nonrepeatable Read)-在同一筆交易中,兩次讀取相同數據,得到內容不同。

事務T1:查詢一筆記錄
         -->事務T2:更新事務T1查詢的記錄
         -->事務T2:呼叫commit進行提交
T1:再次詢問事務上次的記錄
            
#此時事務T1對相同資料查詢了兩次,可獲得的內容不同,稱為無法重複讀取。

注意:不可重複讀取重點在修改。

在基於鎖定的平行控制方法中,如果在執行select時不新增讀鎖,就會發生不可重複讀取問題。

在多版本並行控制機制中,當一個遇到提交衝突的交易需要回退但卻被釋放時,會發生不可重複讀取問題。

有兩個策略可以防止這個問題的發生:

(1) 延遲事務2的執行,直到事務1提交或回退。這種策略在使用鎖時會應用。

(2) 而在多版本並行控制中,事務2可以先提交,而事務1繼續執行在舊版本的資料上。當事務1終於嘗試提交時,資料庫會檢驗它的結果是否和事務1、事務2順序執行時一樣。如果是,則事務1提交成功;如果不是,事務1會被回退。

解決不可重複讀取問題:讀取資料時加上共享鎖,寫資料時加排他鎖,都是交易提交才釋放鎖。讀取時候不允許其他事物修改該數據,不管數據在事務過程中讀取多少次,數據都是一致的,避免了不可重複讀取問題。
4.遺失更新(Lost Update) 

交易T1讀取了數據,並執行了一些操作,然後更新資料。事務T2也做相同的事,則T1和T2更新資料時可能會覆蓋對方的更新,從而造成錯誤。

5.處理上述隔離等級的問題,採用下列方法:

  事務隔離五個層級:
        (1)TRANSACTION_NONE  不使用事務。
        (2)TRANSACTION_READ_UNCOMMITTED  允許髒讀。
        (3)TRANSACTION_READ_COMMITTED  防止髒讀,最常用的隔離等級,且是大多數資料庫的預設隔離等級。
        (4)TRANSACTION_REPEATABLE_READ  可防止髒讀與無法重複讀取。
        (5)TRANSACTION_SERIALIZABLE  可防止髒讀,無法重複讀取和幻讀,(事務串列化)會降低資料庫的效率。

  以上的五個交易隔離等級都是在Connection介面中定義的靜態常數,使用setTransactionIsolation(int level) 方法可以設定交易隔離等級。

  如:con.setTransactionIsolation(Connection.REPEATABLE_READ)。

  注意:交易的隔離等級受資料庫的限制,不同的資料庫支援的隔離等級不一定相同。

 

 

#

以上是髒讀、幻讀、不可重複讀和遺失更新實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板