事務的隔離級別最清晰理解與MVCC實現機制

mysql事物的隔離級別包括四種

                   READ_UNCOMMITTED  spring實現讀未提交 (髒讀)                                 髒讀
                   READ_COMMITTED     spring實現讀已提交 (待解決--不可重複讀+幻讀)  不可重複讀
                   REPEATABLE_READ   spring實現可重複讀 (待解決--幻讀)                       可重複讀
                   SERIALIZABLE     spring實現串行化(已解決)                                             串行化

 

 mysql默認爲不可重複讀,oracle默認爲可重複讀

        髒讀和串行化使我們最容易理解的.假設現在有A、B兩個事務在運行。

       髒讀:在A事務中sql讀取到了B中還沒有進行事務提交的數據。(如果B回滾,那麼A就讀到了錯誤的數據)

       不可重複讀(你在一個事務中不能重複的讀取數據,否則結果出現問題):在A事務中不會讀取到B事務中還沒有提交的數據,避免了髒讀。但是在B事務完成提交後,A事務還沒有完成之前,A又去讀了數據,那麼A讀取的在B提交前後的數據是不一致的。

       可重複讀(你在事務中可以重複的讀取數據):A事務在B事務提交前後讀取的數據一致。也就是說如果A事務在B事務提交前讀取了一次數據,那麼即使B已經更改了數據庫,但是A讀取到的,還是B事務提交之前的數據,這種會導致幻讀。

      串行化:事務串行化,數據與數據庫一致。

       思考:既然我們說 可重複讀 解決了不可重複讀的問題,也就是說我們在一個事務中讀取到的數據都是一致的,不會因爲別的事務提交的數據導致變化,那是不是就說明我們的事務將該行鎖住了,從而避免了其他行對該行的操作呢?

       其實不是的,經測試可以看到,其實數據已經更改了,但是我們讀取的數據依然是以前的數據,這是爲什麼呢,這時因爲mysql採用了MVCC(多版本併發控制)方式。而這種方式讀取的數據會讀取快照(歷史版本),而不會讀取最新版本,但是insert update delete會對當前版本進行操作。

     舉個簡單的例子,如果開啓可重複讀,你在A事務裏兩次讀取一個數據假設爲400,那麼在兩次讀取之間事務B更改了數據減去了50此時數據庫爲350,對A的讀取結果爲400沒有影響,但是如果你在事務A中再讓數據減去50那麼你再在事務A中查詢數據,數據就變成了300.因爲update語句會更新數據。

 

最後來說說 可重複讀 時mysql採用MVCC的實現機制。

其實挺簡單的。這裏值分析一下select的實現,具體的可以看下面的博文

其實在每行數據有面還有兩個列隱藏的行,一行是我們事務的版本號,一行是刪除的標誌

那麼我們上面說了,每次做增刪改的時候,這一行的事務版本號就會更新。

而MVCC告訴我們我們查詢出的數據,都必須滿足兩個條件,

     a.InnoDB只會查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要麼是在事務開始前已經存在的,要麼是事務自身插入或者修改過的.
     b.行的刪除版本要麼未定義,要麼大於當前事務版本號,這可以確保事務讀取到的行,在事務開始之前未被刪除.
只有a,b同時滿足的記錄,才能返回作爲查詢結果.

 

那麼每次連接數據庫的時候開啓事務,他都會給你一個最新的版本號,假設A事務是讀取,那麼A事務在打開讀取了一次所有數據,那麼B事務開動增加一條數據,並提交,這時這條數據的事務版本號是高於A事務的事務版本好的,所以A再查詢也是查詢不到B事務提交的版本號的。

參考:

https://blog.csdn.net/whoamiyang/article/details/51901888

https://www.cnblogs.com/huanongying/p/7021555.html

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章