關於mysql的事務隔離模式、MVCC、next-key,這一篇就夠了

聲明

由於貼mysql截圖會佔太大篇幅,影響整體閱讀理解,所以沒有貼mysql截圖,但是下面步驟都是親自試驗過的

四種隔離級別(由低到高)

  • Read Uncommitted讀未提交:可以看到其他事務未提交的內容
  • Read Committed讀已提交:可以看到其他事務已提交讀內容
  • Repeatable Read可重複度:事務開始時和事務結束時讀到的數據完全相同
  • Serializable串行:事務必須逐步執行,後來的會排隊

隔離級別下的問題

前提條件:同時開啓A和B兩個事務

髒讀:

  1. 事務查詢id爲1的數據,num字段爲1
  2. B事務將id爲1的數據num更新爲2,但未commit
  3. 事務查詢id爲1的數據,num字段變爲2
  4. B回滾,則A讀到的數據爲髒數據

不可重複讀:

  1. 事務查詢id爲1的數據,num字段爲1
  2. B事務將id爲1的數據num更新爲2,commit
  3. 事務查詢id爲1的數據,num字段變爲2
  4. A事務前後兩次讀到的同一條記錄num字段不同,不可重複讀

幻讀:

  1. A事務查詢id >=1 and id <=3的數據,得到id=1和id=3兩條數據(注意:沒有id=2的數據)
  2. B事務插入id=2的數據
  3. A事務再查詢id >=1 and id <=3的數據,發現多了一條id=2的數據,即兩次查詢數據的行數不同

各種隔離模式下會出現的問題

  • 讀未提交:髒讀、不可重複度、幻讀
  • 讀已提交:不可重複讀、幻讀
  • 可重複讀:幻讀

間隙鎖(gap-key)

在一個事務中select for update查詢某條記錄,會鎖定該條記錄的前後空行,什麼叫空行呢,看個例子就知道了

id num
1 2
2 4
3 6
4 7

執行select * from table where num = 4 for update

insert into table ('', 3)和insert into table ('', 5)都會被阻塞,即4前後的空行都無法插入

next-key

由於gap-key只能鎖定記錄之間的間隙,但是我們上面查詢num=4的行也不能被更改,索引該行也會被加行鎖,此時這種既加行速鎖,又加間隙鎖,我們稱之爲next-key

MVCC

  • 事務A:查詢num>=2 and num<=4的記錄,但是不加for update!不加for update!不加for update!
  • 事務B:insert into table ('', 3),不會被阻塞,不會被阻塞,不會被阻塞!然後commit
  • 事務A:查詢num>=2 and num<=4的記錄,和之前查詢相同
  • 事務A:提交
  • 事務A:查詢num>=2 and num<=4的記錄,可以查詢到num=3的記錄,此時返回3條結果

原理:假如事務A在開啓的時候版本號爲2,當更改或者插入數據後,該條記錄的版本號+1,也就是說事務B插入num=3的記錄的版本號爲3,事務A在提交前的所有select都只能查詢到版本號<=2的記錄,也就是說不會產生上面說的幻讀。

MVCC和next-key

看到這裏可能有小夥伴有點蒙了,一會MVCC一會next-key,到底用什麼結局幻讀的???

其實,innodb採用next-key + MVCC去解決幻讀問題的:

  • 在查詢加for update時,會用next-key解決幻讀問題,新的insert和update會阻塞
  • 在查詢不加for update時,會用MVCC解決幻讀問題,新的insert和update不會阻塞

 

 

 

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