透過「鎖」事看InnoDB對並發的處理?

一. 並發場景下的問題

相對於串行處理方式,並發的事務處理可顯著提升數據庫的事務吞吐量、提高資源利用率。在MySQL實際應用中,根據場景的不同,可以分為以下幾類:

  • 讀讀並發
  • 讀寫並發
  • 寫寫並發

在這些場景下,可能會出現更新丟失、臟讀、不可重複度、幻讀的問題。

  • 更新丟失:當多個事務同時更新某1/n行數據時,最後提交的事務會將之前提交的更新覆蓋。
  • 臟讀:一個事務正在插入/更新一行數據,在該事務提交之前,這條數據處於「不一致」狀態。其他事務讀取到這條「臟數據」並據此做進一步處理,就會產生對未提交數據的依賴關係,這種現象稱為臟讀。
  • 不可重複讀:一個事務在查詢某條數據的一定時間後再次查詢該數據,卻發現該條數據已經發生了更新或被刪除,這種現象稱為不可重複讀。
  • 幻讀:一個事務以相同的查詢條件先後兩次查詢數據,第二次查詢結果出現了第一次查詢沒有的新數據,這種情況稱為幻讀。

其中,在各類並發場景下會出現的問題如下:

  • 讀讀並發場景不會導致數據不一致問題,因此無需特殊處理。
  • 讀寫並發場景可能會出現臟讀、不可重複讀、幻讀的問題。
  • 寫寫並發場景可能會出現更新丟失的問題。

二.事務隔離級別

針對上述描述的問題,MySQL採用不同的事務隔離級別分別用於解決上述的部分問題,具體如下:

隔離級別 含義 讀數據一致性 更新丟失 臟讀 不可重複讀 幻讀
讀未提交(Read Uncommitted) 事務中的修改,即使沒有提交,對其他事務依然可見。 最低級別,只能保證不讀取物理上損壞的數據。  否  是   是  是 
讀已提交(Read Committed) 只有已提交事務所做的修改才對其他事務可見。 語句級  否
可重複讀(Repeatable Read ) 同一事務中多次讀取相同的記錄結果時一致的。 事務級  否
串行化(Serializable) 在讀取的每一行數據上加鎖,強制事務串行執行,不支持並發。 事務級  否  否 

 

 

 

 

 

 

 

 

 

 

 

在上述隔離級別中,從上到下並發性能依次降低,安全性依次提高。InnoDB存儲引擎下默認的事務隔離級別是RR,可通過如下SQL查詢事務隔離級別。

select @@global.tx_isolation;

三.事務隔離級別的實現

 InnoDB對事務隔離級別的實現,基本可分為如下兩種或兩種的組合:

1.多版本並發控制(MVCC,Multiversion Currency Control)

MVCC可用來解決讀寫並發場景下的臟讀、不可重複讀問題。具體在不同隔離級別下的應用如下:

  • RC:可解決臟讀問題。
  • RR:可解決臟讀、不可重複讀問題。

具體實現可參考這裡,此處針對鏈接中的文章做簡單補充:

相較於RC,RR之所以能夠解決不可重複讀問題,原因在於RR隔離級別下讀取Read-View是事務級別的,RC是語句級別的。即:RR只在事務開始時讀取一次Read-View,因此一個事務中的多次查詢依賴同一個Read-View,能實現可重複讀。RC級別下每次查詢均讀取     最新的Read-View,無法保證同一事務中先後讀取到的Read-View是相同的,這也是先後讀取到的數據有差異的原因。

2.鎖

鎖是計算機協調多個進程或線程並發訪問某一資源的機制。在數據庫中如何保證數據並發訪問的一致性、有效性是所有數據庫必須解決的一個問題,鎖衝突也是影響數據庫並發訪問性能的一個重要因素。從這個角度來說,鎖對數據了而言顯得尤為重要。

鎖可以解決上述描述讀寫並發場景下的幻讀問題、寫寫並發場景下的更新丟失問題。下面針對鎖、鎖的類型及其應用場景展開詳細描述。

2.1鎖的基本原理

//mysql.taobao.org/monthly/2016/01/01/

//mp.weixin.qq.com/s/yq5Erdv5Dft3foJEVE2dxA

//i6448038.github.io/2019/02/23/mysql-lock/

//www.163.com/dy/article/G0S7FSGG05319WXB.html

 

duplicate key check檢查時需要在二級唯一索引上加gap lock(版本:5.6之前,5.7.26-29之後加record lock)

//juejin.cn/post/6844903597029720072

//my.oschina.net/hebaodan/blog/3045246

 

死鎖發生場景:

  • 事務1,2均獲取某一行數據的s鎖後,均想獲取x鎖。
  • 事務1,2均獲取到某一間隙鎖後,希望進行插入操作,即增加插入意向鎖。
  • 事務1,2操作同一條數據。由於檢索條件不同,事務1,2分別鎖定了聚簇索引和二級索引,然後事務1無法操作二級索引(先刪除,再插入),事務2無法操作聚簇索引,發生死鎖。(參考//mysql.taobao.org/monthly/2016/01/01/)

 

Tags: