【20180613】MySQL innodb 引擎如何解決幻讀

MySQL innodb 引擎如何解決幻度

MySQL innodb 引擎事務的隔離級別有四種,默認是可重複讀(REPEATABLE READ)
  1. 未提交讀(READ UNCOMMITTED)。倆個不同session,一個session正在顯式的開啓事務進行DML操作,但是還沒有提交,另外一個session此時執行SELECT的時候可以讀取得到這個未提交的DML操作之後的值。
  2. 提交讀(READ COMMITTED)。本事務讀取到的是最新的數據(其他的數據提交之後的數據)。就是說在同一個事務內,相同的Query操作獲取得到的結果是不一樣的(倆次查詢期間有新的事務提交)。
  3. 可重複讀(REPEATABLE READ)。同一個事務內,無論執行多少次相同Query查詢的結果是一樣的,不會做任何的修改(哪怕中途有其他的事務有進行DML操作提交)。
  4. 串行化(SERIALIZABLE)。非事務快照讀操作會隱式的獲取LOCK_S共享鎖,可以保證不同事務之間的互斥,只允許併發的讀,併發寫是被禁止的。
MySQL 的髒讀,不可重複讀,幻讀
  1. 髒讀: 一個事務內修改了數據但是還沒有提交,這個時候另外一個事務可以讀取得到這個未提交的數據,這個樣子就被稱之爲髒讀。
  2. 不可重複讀: 一個線程的事務讀取到了另外一個線程中提交的update的數據。
  3. 幻讀: 一個線程中的事務讀取到了另外一個事務insert的數據。
隔離級別和髒讀,不可重複讀,幻讀
隔離級別 髒讀 不可重複讀 幻讀
未提交讀 可能 可能 可能
已提交讀 不可能 可能 可能
可重複讀 不可能 不可能 可能
可串行化 不可能 不可能 不可能

按照上面的邏輯來說的話,MySQL的innodb在可重複讀的情況下是會出現幻讀的現象的,但是實際情況MySQL在可重複讀的隔離級別下是沒有出現幻讀的情況。在可重複讀的情況下MySQL主要是通過MVCC多版本控制來解決可重複讀的情況下幻讀的情況。

快照讀和當前讀

快照讀就是所謂的根據read view去獲取信息和數據,不會加任何的鎖。但是當前讀會獲取得到所有已經提交數據,按照邏輯上來講的話,在一個事務中第一次當前讀和第二次當前讀的中間有新的事務進行DML操作,這個時候倆次當前讀的結果應該是不一致的,但是實際的情況卻是在當前讀的這個事務還沒提交之前,所有針對當前讀的數據修改和插入都會被阻塞,主要是因爲next-key lock解決了當前讀可能會發生幻讀的情況。

next-key lock當使用主鍵索引進行當前讀的時候,會降級爲record lock(行鎖)

Read view

InnoDB支持MVCC多版本,其中RC(READ COMMITTED)和RR(REPEATABLE READ)隔離級別是利用consistent read view(一致讀視圖)方式支持的。所謂的consistent read view就是在某一時刻給事務系統trx_sys打snapshot(快照),把當時的trx_sys狀態(包括活躍讀寫事務數組)記下來,之後的所有讀操作根據其事務ID(即trx_id)與snapshot中trx_sys的狀態做比較,以此判斷read view對事務的可見性。

RR隔離級別(除了GAP鎖之外)和RC隔離級別的差別是創建snapshot時機不同。RR隔離級別是在事務開始時刻,確切的說是第一個讀操作創建read view的;RC隔離級別是在語句開始時刻創建read view的。這就意味着RR隔離級別下面一個事務的SELECT操作只會獲取一個read view,但是RC隔離級別下一個事務是可以獲取多個read view的。

創建/關閉read view需要持有trx_sys->mutex,會降低系統性能,5.7版本對此進行優化,在事務提交時session會cache只讀事務的read view。

下次創建read view,判斷如果是隻讀事務並且系統的讀寫事務狀態沒有發生變化,即trx_sys沒有向前推進,而且沒有新的讀寫事務產生,就可以重用上次的read view。

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