資料庫併發寫入問題-丟失更新與寫入偏差

KD_發表於2020-12-29

MVCC

https://blog.csdn.net/qq_41775852/article/details/104853909
資料庫中的MVCC多版本併發控制(快照隔離)可以避免事務併發時的髒讀、不可重複讀以及幻讀的問題,但是卻無法避免丟失更新以及寫入偏差的問題。

丟失更新和寫入偏差

  • 丟失更新:兩個事務併發讀取同一記錄,並在此基礎上修改記錄,並將其寫回資料庫,第二次寫入的結果會覆蓋第一次寫入的結果,導致資料庫狀態不一致。(丟失更新不僅出現在資料庫中,在應用程式多執行緒併發修改變數、分散式系統多主複製和無主複製中都會遇見)

    例如:以下兩個事務,對A變數進行讀取10,T1事務將其減5,T2事務將其減8,兩事務提交之後,A的狀態為2,即T1事務的更新丟失了。如果A代表賬戶餘額,這種錯誤是不可接受的。
    在這裡插入圖片描述

  • 寫入偏差:寫入偏差可視為丟失更新問題的一般化,如果兩個事務讀取相同的記錄集,然後更新記錄集,不同的事務可能更新(插入、刪除)不同的記錄,則可能發生寫入偏差,導致資料庫狀態不一致或者不符合約束條件。

    比如:1.醫院規定必須至少有一名醫生在值班。而兩個值班醫生同時進行請假事務,由於快照隔離,兩個醫生在檢查當前值班醫生數量時結果都為2,所以他們都可能請假。但是兩個事務提交之後,卻沒有醫生值班了,違反了醫院的規定。2.兩個使用者同時修改唯一使用者名稱,由於快照隔離,兩人都發現資料庫中無重複使用者名稱,則修改成功。兩個修改事務提交後,卻出現使用者名稱衝突。
    在這裡插入圖片描述
    如果併發事務沒有先讀取記錄集的值,而是直接寫入新的記錄集值,個人認為不屬於丟失更新或者寫入偏差,因為這導致的資料庫不一致,是使用者的錯誤邏輯所導致的,不是事務併發的原因。

丟失更新和寫入偏差的原因是相同的:併發事務首先查詢得到了相同的記錄集,然後根據此記錄集進行更新、插入、刪除等動作。由於快照隔離,事務感受不到其他事務對記錄集的更改,所以可以成功提交事務。但是併發事務的修改卻出現了矛盾,導致資料庫不一致。

解決方法

CAS

比較並設定(CAS, Compare And Set)是一種原子操作,此操作的目的是為了避免丟失更新:只有當前值從上次讀取時一直未改變,才允許更新發生。如果當前值與先前讀取的值不匹配,則更新不起作用,且必須重試讀取-修改-寫入序列。但是在提供快照隔離的事務中不起作用

顯示鎖定

由於併發事務的更改都是基於讀取到的記錄集,所以只要事務對讀取到的記錄集加排他鎖,然後再對記錄集更新,提交事務之後才釋放排他鎖。這樣併發事務就只能讀取到其他事務以及提交後的資料,則不會出現不一致的狀態。

比如對於醫生請假事務,讀取並鎖定所有醫生的值班狀態,修改自己的值班狀態為請假,提交事務後釋放鎖。則第二個醫生在請假事務中讀取所有醫生值班狀態會阻塞,直到上一個事務提交,發現只剩自己一個人值班,則無法請假。

序列化隔離級別

使用事務的序列化隔離級別可以避免丟失更新和寫入偏差。

相關文章