Innodb的RR到底有沒有解決幻讀?看不懂你打我!
關於Innodb中的REPEATABLE READ這種隔離級別到底有沒有解決幻讀?好像眾說紛紜,大家的說法都不一致。
有的人說,RR當然沒解決幻讀了,因為只有Serializable才能解決幻讀。
也有人說,RR解決了幻讀,因為RR中加了間隙鎖,就能解決幻讀的問題。
還有人說,只有間隙鎖是沒用的,還有MVCC也幫助RR解決了幻讀的問題。
那到底真實情況是怎麼樣的呢?
我認為,InnoDB中的REPEATABLE READ這種隔離級別透過間隙鎖+MVCC解決了大部分的幻讀問題,只有一種特殊的幻讀情況無法解決。
為什麼這麼說呢?這種特殊情況是怎麼回事兒呢?本文就來把這個問題講清楚。(本文中所有SQL的執行環境是MySQL 5.7.9 及MySQL 8.0.30)
在介紹如何解決幻讀之前,有必要再明確一下什麼是幻讀,確保大家理解是一致的。
幻讀就是事務在做範圍查詢(SELECT)的過程中,有另外一個事務對範圍內新增了記錄(INSERT),導致範圍查詢的結果條數不一致的現象。
有這樣一張表:
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT,
gmt_create DATETIME NOT NULL,
age INT NOT NULL,
name VARCHAR(16) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
INSERT INTO users(gmt_create,age,name) values(now(),18,'Hollis');
INSERT INTO users(gmt_create,age,name) values(now(),28,'HollisChuang');
INSERT INTO users(gmt_create,age,name) values(now(),38,'Hollis666');
接著我們進行如下操作:
在這個例子中,在事務1中執行了兩次相同的查詢操作。但是兩次操作中間事務2向資料庫中增加了一條符合事務1的查詢條件的資料,最終事務1的兩次查詢得到的結果是不一樣的,這種現象就是幻讀。
MVCC,是Multiversion Concurrency Control的縮寫,翻譯過來是多版本併發控制,和資料庫鎖一樣,他也是一種併發控制的解決方案。它主要用來解決讀-寫併發的情況。關於MVCC的原理可以參考《再有人問你什麼是MVCC,就把這篇文章發給他!》
我們知道,在MVCC中有兩種讀,一種是快照讀、一種是當前讀。
所謂快照讀,就是讀取的是快照資料,即快照生成的那一刻的資料,像我們常用的普通的SELECT語句在不加鎖情況下就是快照讀。
SELECT * FROM xx_table WHERE ...
在 RC 中,每次讀取都會重新生成一個快照,總是讀取行的最新版本。 在 RR 中,快照會在事務中第一次SELECT語句執行時生成,只有在本事務中對資料進行更改才會更新快照。
那麼也就是說,如果在RR下,一個事務中的多次查詢,是不會查詢到其他的事務中的變更內容的,所以,也就是可以解決幻讀的。
所以,針對上面的例子,如果我們把事務隔離級別設定為RR,那麼因為有了MVCC的機制,就能解決幻讀的問題:
可以看到,同一個事務中的兩次查詢結果是一樣的,就是在RR級別下,因為有快照讀,所以第二次查詢其實讀取的是一個快照資料。
上面我們講過了MVCC能解決RR級別下面的快照讀的幻讀問題,那麼當前讀下面的幻讀問題怎麼解決呢?
當前讀就是讀取最新資料,所以,加鎖的 SELECT,或者對資料進行增刪改都會進行當前讀,比如:
SELECT * FROM xx_table LOCK IN SHARE MODE;
SELECT * FROM xx_table FOR UPDATE;
INSERT INTO xx_table ...
DELETE FROM xx_table ...
UPDATE xx_table ...
舉一個下面的例子:
像上面這種情況,在RR的級別下,當我們使用SELECT … FOR UPDATE的時候,會進行加鎖,不僅僅會對行記錄進行加鎖,還會對記錄之間的間隙進行加鎖,這就叫做間隙鎖(參考:資料庫的鎖,到底鎖的是什麼?)。因為記錄之間的間隙被鎖住了,所以事務2的插入操作就被阻塞了,一直到事務1把鎖釋放掉他才能執行成功。
因為事務2無法插入資料成功,所以也就不會存在幻讀的現象了。所以,在RR級別中,透過加入間隙鎖的方式,就避免了幻讀現象的發生。
前面我們介紹了快照讀(無鎖查詢)和當前讀(有鎖查詢)下是如何解決幻讀的問題的,但是,上面的例子就是幻讀的所有情況了嗎?顯然並不是。
我們說MVCC只能解決快照讀的幻讀,那如果在一個事務中發生了當前讀,並且在另一個事務插入資料前沒來得及加間隙鎖的話,會發生什麼呢?
那麼,我們稍加修改一下上面的SQL程式碼,透過當前讀的方式進行查詢資料:
在上面的例子中,在事務1中,我們並沒有在事務開啟後立即加鎖,而是進行了一次普通的查詢,然後事務2插入資料成功之後,再透過事務1進行了2次查詢。
我們發現,事務1後面的兩次查詢結果完全不一樣,沒加鎖的情況下,就是快照讀,讀到的資料就和第一次查詢是一樣的,就不會發生幻讀。但是第二次查詢加了鎖,就是當前讀,那麼讀取到的資料就有其他事務提交的資料了,就發生了幻讀。
那麼,如果你理解了上面的這個例子,並且你也理解了當前讀的概念,那麼你很容易就能想到,下面的這個CASE其實也是會發生幻讀的:
這裡發生幻讀的原理,和上面的例子其實是一樣的,那就是MVCC只能解決快照讀中的幻讀問題,而對於當前讀(SELECT FOR UPDATE、UPDATE、DELETE等操作)還是會產生幻讀的現象的。
UPDATE語句也是一種當前讀,所以它是可以讀到其他事務的提交結果的。
為什麼事務1的最後一次查詢和倒數第二次查詢的結果也不一樣呢?
是因為根據快照讀的定義,在RR中,如果本事務中發生了資料的修改,那麼就會更新快照,那麼最後一次查詢的結果也就發生了變化。
那麼瞭解了幻讀的解決場景,以及不能解決的幾個CASE之後,我們來總結一下該如何解決幻讀的問題呢?
首先,如果想要徹底解決幻讀的問題,在InnoDB中只能使用Serializable這種隔離級別。
圖源:MySQL 8.0 Reference Manual
那麼,如果想在一定程度上解決或者避免發生幻讀的話,使用RR也可以,但是RC、RU肯定是不行的。
在RR級別中,能使用快照讀(無鎖查詢)的就使用快照讀,這樣不僅可以減少鎖衝突,提升併發度,而且還能避免幻讀的發生。
那麼,如果在併發場景中,一定要加鎖的話怎麼辦呢?那就一定要在事務一開始就立即加鎖,這樣就會有間隙鎖,也能有效的避免幻讀的發生。
但是需要注意的是,間隙鎖是導致死鎖的一個重要根源~所以,用起來也需要慎重。
在RC級別中,幻讀是沒有辦法解決的,因為RC中快照讀是每一次都會重新生成快照,並且RC中也不會有間隙鎖。
在RR級別中,因為有MVCC機制,對於普通的無鎖查詢,這種是屬於快照讀的,RR的快照讀在同一個事務中只會讀一次,所以在事務過程中,其他事務的變更不會影響到當前事務的查詢結果。所以這種幻讀是可以解決的。
當時,MVCC只能對快照讀起作用,而對於加鎖的讀請求,這種屬於當前讀,當前讀的話是可以查詢到其他事務的變更的,所以會產生幻讀。
想要解決幻讀,可以使用Serializable這種隔離級別,或者使用RR也能解決大部分的幻讀問題。
在RR級別下,為了避免幻讀的發生,要麼就是使用快照讀,要麼就是在事務一開始就加鎖。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024923/viewspace-2929635/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- BIO、NIO、AIO區別(看不懂你打我)AI
- InnoDB 是如何解決幻讀的
- MySQL rr下幻讀問題分析MySql
- 【面試普通人VS高手系列】innoDB如何解決幻讀面試
- 投屏沒聲音?我有解決方法!
- webpack 優化react專案沒有解決的問題Web優化React
- 讀懂你的腦電波
- 利用動態規劃實現最短路徑和(適合小白看,看不懂你打我,附JS程式碼和C程式碼實現)動態規劃JSC程式
- 萬字長文詳解Spring5架構教程,還不懂你打我!!Spring架構
- 看不懂來打我,Vue3的watch是如何實現監聽的?Vue
- 記一次mysql熱備份xtrabackup(沒有解決問題)MySql
- 圖解程式執行緒、互斥鎖與訊號量-看完不懂你來打我圖解執行緒
- 看不懂來打我,Vue3的watch是如何實現監聽的?KNVue
- MySQL的可重複讀級別能解決幻讀嗎MySql
- 看不懂來打我!讓效能提升56%的Vue3.5響應式重構Vue
- MySQL是怎麼解決幻讀問題的?MySql
- 終於解決了《====》記一次mysql熱備份xtrabackup(沒有解決問題)MySql
- 沒有解析的域名可以申請SSL證書嗎
- 看不懂來打我,vue3如何將template編譯成render函式Vue編譯函式
- 面試官:MySQL的幻讀是怎麼被解決的?面試MySql
- 詳解MVCC以及儘可能解決幻讀的兩種方案MVC
- 髒讀,幻讀,不可重複讀
- 資料庫系列:RR和RC下,快照讀的區別資料庫
- require的到底有沒有返回值?UI
- Java程式語言慶祝成立25週年,還沒有解決5年前的問題 - infoworldJava
- Spring Cache 缺陷,我好像有解決方案了Spring
- 髒讀、幻讀和不可重複讀
- 什麼是鎖?深入分析解讀MySQL鎖,解決幻讀問題!MySql
- 人工智慧到底有沒有泡沫?人工智慧
- Phantom Problem(幻讀)問題
- 髒讀、幻讀和不可重複讀?為啥?
- 什麼是髒讀,不可重複讀,幻讀
- win10系統玩夢幻西遊沒有聲音了的解決方法Win10
- win10系統wifi無速度怎麼辦 win10連上wifi網速沒有解決方法Win10WiFi
- 軟體測試到底有沒有出路
- MySQL 配置InnoDB為只讀操作MySql
- Mysql RC/RR隔離原理和區別 不可重複讀和可重複讀MySql
- 找回丟失的 commit 要記住不要慌 事情總有解決的方法MIT