innodb解決幻讀


1. 結論
首先說結論,在RR的隔離級別下,Innodb使用MVVC和next-key locks解決幻讀,MVVC解決的是普通讀(快照讀)的幻讀,next-key locks解決的是當前讀情況下的幻讀。

 

2. 幻讀是什么
事務A,先執行:

update table set name=“hh” where id>3;

結果為:

OK row xx 表名成功影響多少行數據

 

事務B,后執行,並且提交:

insert into table values(11, uu);

commit;

 

事務A,然后再select一下:

select * from table where id>3

結果集為:

11,uu

事務A懵了,我特么不是id>3全部更新了嗎

這次是已提交事務B對事務A產生的影響,這個影響叫做“幻讀”。

幻讀和不可重復讀的區別是,前者是一個范圍,后者是本身

3. 怎么解決的?
3.1. 當前讀
所謂當前讀,指的是加鎖的select(S或者X), update, delete等語句。在RR的事務隔離級別下,數據庫會使用next-key locks來鎖住本條記錄以及索引區間。

拿上面那個例子來說,在RR的情況下,假設使用的是當前讀,加鎖了的讀

select * from table where id>3 鎖住的就是id=3這條記錄以及id>3這個區間范圍,鎖住索引記錄之間的范圍,避免范圍間插入記錄,以避免產生幻影行記錄。

 

3.2. 普通讀
因為普通讀是不會加鎖的讀,故不會有next-key locks的使用,解決幻讀的手段是MVVC

mvvc會給每行元組加一些輔助字段,記錄創建版本號和刪除版本號。

而每一個事務在啟動的時候,都有一個唯一的遞增的版本號。每開啟一個新事務,事務的版本號就會遞增。

默認的隔離級別(REPEATABLE READ)下,增刪查改變成了這樣:

SELECT
讀取創建版本小於或等於當前事務版本號,並且刪除版本為空或大於當前事務版本號的記錄。這樣可以保證在讀取之前記錄是存在的
INSERT
將當前事務的版本號保存至行的創建版本號
UPDATE
新插入一行,並以當前事務的版本號作為新行的創建版本號,同時將原記錄行的刪除版本號設置為當前事務版本號
DELETE
將當前事務的版本號保存至行的刪除版本號
 

比如我插入一條記錄, 事務id 假設是1 ,那么記錄如下:也就是說,創建版本號就是事務版本號。

id

name

createversion

deleteversion

1 wxt 1  
 

如果我更新的話,事務id假設是2

id

name

createverison

deleteversion

1 wxt 1 2
1 taotao 2  
這里是把name更新為taotao,原來的元組deleteversion版本號為這個事務的id,並且新增一條

 

如果我刪除的話,假設事務是id=3

id

name

createverison

deleteversion

1 taotao 2 3
就變成現在這個樣子

 

關鍵點來了

現在我讀取的話,必須同時滿足兩個條件的

讀取創建版本小於或等於當前事務版本號   這意味着數據在這個事務之前被創建
刪除版本為空或大於當前事務版本號的記錄。  這意味着刪除操作在這個事務之后發生
 

就拿上面那個例子說明

當前數據庫的狀態

 

id

name

createverison

deleteversion

4
a

2  
5 b 5  

假設事務A的id=10

現在update table set name=“hh” where id>3;執行這條語句

 

id

name

createverison

deleteversion

4
a

2 10
5 b 5 10
4
hh

10  
5 hh 10  
 

事務B的id=11

insert into table values(11, uu);

 

id

name

createverison

deleteversion

4
a

2 10
5 b 5 10
4
hh

10  
5 hh 10  
11 uu 11  
 

 

最后事務A(id=10)在此讀取

 

select * from table where id>3

根據上述的規則,

讀取創建版本好小於等於當前事務的→那么(4,a)(5,b)(4,hh)(5,hh)

上面規則的輸出作為下面規則的輸入的話

刪除版本為空或大於當前事務版本號的記錄→(4,hh)(5,hh)

如此讀取就沒有讀取到事務B新插入的那行,解決幻讀

 

 

如果事務B是更新id=4 的元組name=cc呢

同理,根據update的規則

id

name

createverison

deleteversion

4
a

2 10
5 b 5 10
4
hh

10 11
5 hh 10  
4 cc 11  
 


然后根據select的規則去讀取的話,得到的還是(4,hh)(5,hh)

4. 多說一句
在RC的模式下,MVVC解決不了幻讀和不可重復讀,因為每次讀都會讀它自己刷新的快照版本,簡單來說就是另一個事務提交,他就刷新一次,去讀最新的
————————————————
版權聲明:本文為CSDN博主「Aaron_濤」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_33330687/article/details/89004462


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM