Mysql InnoDB多版本并發控制MVCC

參考書籍《mysql是怎樣運行的》系列文章目錄和關于我
一丶為什么需要事務隔離級別mysql是一個客戶端/服務斷軟件 , 對于同一個服務器來說,可以有多個客戶端進行連接,每一個客戶端進行連接之后就形成一個會話,每一個客戶端都可以在自己的會話中向服務器發出請求語句,一個請求語句可能是某一個事務的一部分,服務器可以同時處理多個事務 。
如果事務時一個接著一個進行 , 那么下一個事務是在上一個事務的一致性前提下進行的,就沒用一致性的問題,但是事務是并發進行且可能訪問到相同的數據這時候就會出現如下問題

Mysql InnoDB多版本并發控制MVCC

文章插圖
可以看到AB最開始總和13元,最后AB總和18元,銀行血虧五元,這顯然違背了一致性——錢的總量不變 。這就是并發情況下兩個事務的影響,所以需要事務隔離讓事務隔離的進行,互不干涉 。
1.實現事務隔離的方式:串行執行【Mysql InnoDB多版本并發控制MVCC】最簡單直接的方式,同一時間只能有一個事務運行,這樣必然不會有上述不一致的情況,但是大大降低了吞吐率并增加了事務的等待時間
2.實現事務隔離的方式:可串行執行并發事務之所以出現不一致的情況,就是由于多個事務訪問相同的數據,需要實現多個事務在訪問相同數據的時候進行限制,比方說上圖中事務2想訪問A賬戶的值需要等待事務提交事務之后,這樣可以讓并發事務的執行如同串行執行的效果一樣 。
二丶并發事務執行的問題:臟寫 , 臟讀,不可重復讀,幻讀1.臟寫一個事務修改了另外一個未提交事務修改過的數據
  • 臟寫導致一致性無法保證
    Mysql InnoDB多版本并發控制MVCC

    文章插圖
    上圖事務A和事務B都更新紫色數據,其中事務A首先更新為A,然后事務B過來更新為B,這時候事務A回滾后更新為Null,事務 B 明明正常寫了一行數據,但是寫完之后發現值變了,有點丟失更新的意思 。(比如A表示余額,這時候在將余額A判斷是否足以支付,判斷得到可以,事務B執行扣費寫入A-5,商家收到5元,結果這時候回滾了,A變成Null,事務A中轉錢的一方錢變為A,錢的總額變為A+5了)
  • 臟寫導致原子性受到破壞
    假如上述的事務B還操作了另外的數據,比如插入一條數據C,并且更改為B寫入C是在一個事務下面的,需要具備原子性 , 但是臟寫讓B的更改需要部分回滾為Null,這樣插入C和更改B就不具備原子性(比如A表示余額,這時候在將余額A判斷是否足以支付,判斷得到可以 , 事務B執行扣費寫入A-5 , 商家收到5元 , 結果這時候回滾了,A變成Null , 這時候部分回滾,商家的5元沒用回滾,商家的庫存也沒用回滾,原子性被破壞)
2.臟讀如果一個事務讀取到另外一個事務未提交的數據,意味著發生了臟讀
Mysql InnoDB多版本并發控制MVCC

文章插圖
比如事務A先寫數據A,然后事務B督導數據A后在內存中使用A進行一系列操作(比如A表示余額,這時候在將余額A判斷是否足以支付,判斷得到可以)但是事務A這時候回滾了,事務B再次讀取數據發現為null,這就是臟讀 。
臟讀可能引發一致性的問題:比如事務操作時修改x和y的值,并且二者總是相等的,A修改x為1,還沒來得及修改y也沒用提交事務,這時候事務B讀取x=1,y=0,二者不等,事務B讀取到了數據庫不一致的狀態,讀取到未提交事務的值
3.不可重復讀假如一個事務修改了另外一個事務未提交的數據,意味發生了不可重復讀
Mysql InnoDB多版本并發控制MVCC

文章插圖
比如事務A第一次讀取到值為A,接著事務B修改為B , 并且提交了事務B,然后事務A再次讀取得到的數據是B,同一行數據多次讀取值并不相同,這稱作不可重復讀 。它是指在同一個事務里面查詢同一行數據,每次查到的數據都不一樣 。和臟讀區別在于臟讀是由于別的事務回滾導致,而不可重復讀讀到的其實是已經提交的數據 。
事務A讀到事務B提交后的數據似乎很合理 , 但是我們想象這樣一種場景:你有一個流水表和用戶余額 , 其中記錄用戶每天的流水,你在月初0點的時候核對流水和庫存,但是流水很多,你的程序選擇一個一個用戶的進行核對,核對用戶甲,甲沒做任何消費,但是當你核對B的時候,你將B的流水load到內存中,但是B這時候(0點30分,這一筆數據新的一個余額)進行了扣除余額的操作,導致B余額和流水對不上了 。

推薦閱讀