InnoDB的RR隔離級別能否防止「幻讀」

2021-10-11 21:32:18 字數 1796 閱讀 4224

一、快照讀和當前讀(參考這篇文章)

在rr級別中,通過mvcc機制,雖然讓資料變得可重複讀,但我們讀到的資料可能是歷史資料,不是資料庫最新的資料。這種讀取歷史資料的方式,我們叫它快照讀(snapshot read),而讀取資料庫最新版本資料的方式,叫當前讀(current read),這兩者是衝突的。

1.快照讀

當執行select操作時,innodb預設執行快照讀,會記錄下這次select後的結果,之後select 的時候就會返回這次快照的資料,即使其他事務提交了不會影響當前select的資料,這就實現了可重複讀了(innodb預設隔離級別是可重複讀,和這個說法一致)。快照的生成時機是在第一次執行select的時候,也就是說假設當a開啟了事務,然後沒有執行任何操作,這時候b insert了一條資料然後commit,這時候a執行 select,讀到的資料中就會有b新增的那條資料。之後無論再有其他事務commit都沒有關係,因為快照已經生成了,後面的select都是根據快照來的。

先提一句:快照讀是通過mvcc和undo log實現的,暫不展開

2.當前讀

對於會修改資料的操作(update、insert、delete)都是採用當前讀的模式,通過加鎖來保證增刪改的資料無法通過其他事務訪問。在執行這幾個操作時會讀取最新的記錄,即使是別的事務提交的資料也可以查詢到。假設要update一條記錄,但是在另乙個事務中已經delete掉這條資料並且commit了,如果update就會產生衝突,所以在update的時候需要知道最新的資料(例子可參考這篇文章的「試驗一」)

那麼如何使用select操作實現當前讀呢?答案是需要手動加鎖(例子可參考這篇文章的「試驗四」)

select

*from

table

where ? lock

inshare

mode

;select

*from

table

where ? for

update

;

二、select for update 和 select lock in share mode

select…lock in share在select的結果集上加乙個共享鎖.允許其他會話讀取這些資料,但不允許修改.

select…for update 將讀取的結果集加乙個排他鎖. 阻止其他會話讀或寫該結果集.

而這裡加的鎖是next-key lock

三、當前讀時如何避免幻讀

當前讀是通過next-key lock實現,next-key lock會鎖住乙個範圍,並且鎖定記錄本身,使得其他事務不能操作鎖定範圍內的記錄,也就杜絕了出現「幻影」。(因為其他事務根本無法在此範圍裡插入資料)

四、快照讀時如何避免幻讀

呵呵,快照讀時沒有避免幻讀,只是在select時都是讀到歷史資料,看起來是沒有幻讀,但是當你更新時,發現,明明沒有這條資料呀?!(例子可參考這篇文章中的「試驗一」和「試驗二」)

五、結論

在innodb的rr隔離級別下

1.對於快照讀,通過mvcc實現了重複讀,但是沒有完全避免幻讀,只是在簡單select時避免了幻讀

2.要完全避免幻讀,需要手動加鎖進行當前讀,這時會使用next-key lock避免幻讀

innodb事務隔離級別

事務隔離級別 sql標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低階別的隔離級一般支援更高的併發處理,並擁有更低的系統開銷。read uncommitted 讀取未提交內容 在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用...

InnoDB事務隔離級別

會話1 會話2begin begin update table set age 10 where id 1 select age from table where id 1 commit commit rollback 會話2將age的值改變,且並未提交,此時會話1select查詢結果為10.如果會...

innodb 四種隔離級別

read uncommitted,read committed,repeatable read,serializable.預設隔離級別是repeatable read 特性1.一致性讀的方式是在第一次讀時建立快照 特性2.在鎖定讀 update delete時,加鎖方式依賴於查詢的方式,即是否是根據...