關於innodb下,幻讀是如何被解決的

innodb下幻讀是如何在RR級別下被解決的?

先來簡單的複習一下數據庫隔離級別html

  1. RU(Read Uncommitted)

一個事務A讀取到另外一個事務B未提交的修改,B回滾了,就形成了數據不一致。(現象:髒讀)git

  1. RC(Read Committed)

一個事務A在事務執行過程當中第一次讀取的值和第二次讀取的值不一致,這是因爲事務B在倆次讀取之間修改了數據並提交了事務。(現象:不可重複讀)github

  1. RR(Repeatable Read)

一個事務A在事務執行過程當中第一次讀取的值和第二次讀取的值一致(解決了不可重複讀),可是其餘事務B 的insert 或者 delete的操做,會影響到倆次查詢的條數(現象:幻讀)數據庫

  1. Serializable

最高的事務隔離級別,串行化。bash


問題來了:RR下會出現幻讀,那爲何innodb能在RR下解決幻讀呢?不是互相矛盾嗎?併發

解釋:這是因爲innodb和標準不一致致使的。具體能夠看看github火熱的討論Innodb RR 下可否防止幻讀?ui

結論:RR 下,innodb下的幻讀是由MVCC 或者 GAP 鎖 或者是next-key lock 解決的。

關於MVCC 能夠查看這篇文章 MVCC原理

意思就是MVCC判斷了記錄的可見性,好比 select count(*) from table where col_name = xxx 時(屬於快照讀),在RR 級別下,這條事務在事務一開始就生成了readview,經過這個readview 這條語句將會找到符合條件的行而且計算數量。 那麼關於與如何找到這些符合條件的行,知足where 條件的同時也得知足本事務對這些行的可見性。 因此在同一事務裏並不會產生幻讀的現象。spa

關於GAP 鎖 能夠查看這篇文章next-key lock

在這裏咱們須要瞭解 當前讀快照讀 的區別code

  1. 快照讀:簡單的select操做,屬於快照讀,不加鎖。 select * from table where ?;htm

  2. 當前讀:特殊的讀操做,插入/更新/刪除操做,屬於當前讀,須要加鎖。
    select * from table where ? lock in share mode;
    select * from table where ? for update;
    insert into table values (…);
    update table set ? where ?;
    delete from table where ?;

    全部以上的語句,都屬於當前讀,讀取記錄的最新版本。而且,讀取以後,還須要保證其餘併發事務不能修改當前記錄,對讀取記錄加鎖。其中,除了第一條語句,對讀取記錄加S鎖 (共享鎖)外,其餘的操做,都加的是X鎖 (排它鎖)。

咱們來如下倆段僞代碼:

//code 1
beginTransaction

delete * from table where id = ?  (加了二級索引(不是惟一索引))

endTransaction


//code 2
beginTransaction

select count(*) from table where id = ? for update (加了二級索引(不是惟一索引))

endTransaction

複製代碼
  1. code 1 的分析:
    因爲delete * from table where id = ? 這是當前讀,它會鎖定一個範圍採用GAP 鎖的方式,讓符合條件的範圍內不得讓其餘事務插入數據,這樣也就解決了幻讀。
  2. code 2 的分析:
    因爲select count(*) from table where id = ? for update 雖然也是當前讀,可是它加的鎖是next-key-lock,它是由GAP鎖和record鎖組成的,因此它也能鎖定範圍不讓其它事務插入符合條件的數據,鎖定記錄自己,也不讓其它事務修改數據。這樣也就避免了幻讀。
相關文章
相關標籤/搜索