【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解決了當前讀可能會發生幻讀的狀況。session

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對事務的可見性。ide

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。線程

相關文章
相關標籤/搜索