目錄
- 概述
- MVCC做了什么
- 鎖做了什么
- 為啥幻讀:
- 參考資料:
概述
筆者在學習資料庫相關內容時,發現關于innoDB在RR級別下究竟能不能保證不發生幻讀這個問題,網上的資料眾說紛紜,筆者在經過總結和自己的試驗之后,在這里結合自己的理解分析一下這個問題,若有謬誤,歡迎指正,筆者在這里默認讀者都了解了關于幻讀以及innoDB中MVCC和鎖機制的情況,僅對該問題進行分析,
先說結論,innoDB的RR級別下仍然會出現幻讀的情況,但是innoDB還是通過MVCC和鎖盡可能避免幻讀發生,
MVCC做了什么
首先,關于MVCC,在RR級別下,MVCC只會在事務的首個查詢發生時生成一個Read View,后續的相同查詢都是共用這個Read View,這樣就實作了可重復讀,同時不難想到,這也解決了幻讀,因為即使另一個事務成功插入并提交,該版本在首次生成的Read View中也是不可見的,但是我們要強調的是,這僅僅是解決了快照讀的幻讀問題,如果事務中只有快照讀,那么RR級別下不會有幻讀問題,
鎖做了什么
其次,innoDB通過間隙鎖來盡量避免幻讀問題,這里簡單舉一個網上常見的例子
CREATE TABLE `test_RR` (
`id` INT NOT NULL,
`teacher_id` INT NULL,
`class_id` INT NULL,
`name` VARCHAR(6) NULL,
PRIMARY KEY (`id`),
INDEX `teacher_id` (`teacher_id` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
| transaction A | transaction B | |
|---|---|---|
| 1 | begin; | |
| 2 | select * from test_RR where teacher_id=1; | |
| 3 | update test_RR set name='zhang' where teacher_id=1; | |
| 4 | begin; | |
| 5 | insert into test_RR values (12,2,6,'zhang'); |
經過測驗,這里的陳述句5會被阻塞,因為陳述句3 update是當前讀操作,給表中加了間隙鎖,和B的插入操作互斥,
為啥幻讀:
然而,還有一種情況會導致幻讀
| transaction A | transaction B | |
|---|---|---|
| 1 | begin; | |
| 2 | select * from test_RR where teacher_id=1; | |
| 3 | begin; | |
| 4 | insert into test_RR values (12,1,6,'zhang'); | |
| 5 | commit; | |
| 6 | update test_RR set name='wang' where teacher_id=1; | |
| 7 | select * from test_RR where teacher_id=1; | |
| 8 | commit ; |
陳述句2結果:

陳述句7結果:

這里還是產生了幻讀問題,關鍵在于陳述句6 update是當前讀,故而將事務B插入提交的行也讀了進來進行了更新,最要命的是讓該行有了一個版本號為當前事務id的版本,這樣陳述句7查詢的時候自然就將它讀了進來,導致了幻讀問題,
參考資料:
面試被反問,RR級別下能解決幻讀問題那為什么不叫幻讀級別?_扭秧歌的一只泱的博客-CSDN博客
Innodb中的事務隔離級別和鎖的關系 - 美團技術團隊 (meituan.com)
幻讀在 InnoDB 中是被如何解決的? - 來份鍋包肉 - 博客園 (cnblogs.com)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/543244.html
標籤:MySQL
上一篇:DataX插件二次開發指南
