1. 程式人生 > 其它 >MySQL事務併發可能帶來的問題及其解決方案

MySQL事務併發可能帶來的問題及其解決方案

併發事務處理能大大增加資料庫資源的利用率,提高資料庫系統的事務吞吐量,從而可以支援更多使用者。

但是同時會帶來諸多問題
1、更新丟失(Lost Update)
兩個或者多個事務同時選擇同一行資料,都基於最初選定的值更新該行,由於每個事務都不知道其它事務的存在,就會發生更新丟失的問題。最後提交的更新覆蓋了之前其它事務所做的更新。

2、髒讀(Dirty Reads)
一個事務正在對一條記錄進行修改,這個事務完成並提交前,這條記錄的資料就處於不一致的狀態。此時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”資料,
並依據此做了進一步的處理,就會產生對未提交的資料的依賴關係。這種現象就叫做“髒讀”。
總結:事務A讀取到了事務B已經修改但尚未提交的資料,還在這個資料基礎上做了操作。此時,如果B事務回滾,A讀取的資料無效,不符合一致性要求。

3、不可重複讀(Non-Repeatable Reads)
一個事務在讀取某些資料後的某個時間,再次讀取以前讀過的資料,卻發現其讀出的資料已經發生了改變、或某些記錄已經被刪除了!這種現象就叫做“不可重複讀”,重複讀到的是不同的資料。
總結:事務A讀取到了事務B已經提交的修改資料,不符合隔離性。

4、幻讀(Phantom Reads)
一個事務按相同的查詢條件重新讀取以前檢索過的資料,卻發現其他事務插入了滿足其查詢條件的新資料,這種現象就稱為“幻讀”。
舉個例子:比如事務A第一次查詢到表Student中有a、b、c三條資料,然後事務B向裡面新增一條d資料,事務A再按照原來的查詢條件查詢發現查詢出四條資料,這讓事務A產生幻想,之前
明明就只有三條資料,為什麼現在卻有四條資料了呢?
總結:事務A讀取到了事務B提交的新增資料,不符合隔離性。

解決方案:
解決更新丟失主要有以下兩個方式:

  1. 使用事務+鎖定讀,也就是for update
  2. 不使用事務,用CAS自旋來操作

髒讀、不可重複讀和幻讀其實都是資料庫讀一致性問題,必須由資料庫提供一定的事務隔離機制來解決。那有哪些隔離級別呢?主要有以下四種隔離級別:

隔離級別 髒讀 不可重複讀 幻讀
讀未提交(Read uncommitted) 不能解決 不能解決 不能解決
讀已提交(Read committed) 可以解決 不能解決 不能解決
可重複讀(Repeatable read) 可以解決 可以解決 不能解決
可序列化(Serializable) 可以解決 可以解決 可以解決

假設現在有兩個事務,事務A和事務B,那麼上面的四種隔離級別是什麼意思呢?
1、讀未提交(Read uncommitted)
字面意思,就是可以讀到別的事務未提交的資料,也就是事務A可以讀取事務B未提交的資料,這種情況肯定可能會導致髒讀、不可重複度和幻讀。

2、讀已提交(Read committed)
字面意思,就是隻可以讀到別的事務已提交的資料,也就是事務A只可以讀取到事務B已經提交了的資料,那麼在B未提交之前的資料是讀取不到的,也就不可能產生髒讀,但是因為事務B已提交的
資料是可以讀取到的,所以可能會導致不可重複讀和幻讀。

3、可重複讀(Repeatable read)
字面意思,就是事務可以重複讀取資料,在事務期間,每次讀取的資料都是一樣的,也就是事務A開啟事務後,讀取了某一個表的5條資料,不管你事務B怎麼對這5條資料修改操作,我事務A每次
查詢都是5條一摸一樣的資料,所以是可重複讀的,因此不可能導致髒讀,不可重複讀,但是還是可能導致幻讀的。

4、可序列化(Serializable)
mysql中事務隔離級別為serializable時會鎖表,因此不會出現幻讀的情況,這種隔離級別併發性極低,開發中很少會用到。

擴充套件:
我們都知道MySQL預設的隔離級別是可重複讀(Repeatable read),那為什麼不會產生幻讀呢?
原因:MySQL在可重複讀(Repeatable read)隔離級別的情況下使用了next-key Lock鎖演算法,因此可以避免幻讀的產生。next-key Lock鎖,鎖定的不是單個值,而是一個範圍(GAP),
並且鎖定記錄本身。對於行的查詢,都是採用該方法。