幻讀是什麼?

爲了便於進行解釋幻讀,新建一張表進行詳細闡述:

CREATE TABLE `t` (
 `id` int(11) NOT NULL,
 `c` int(11) DEFAULT NULL,
 `d` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

如果我們執行下面的查詢:

begin;
select * from t where d=5 for update;
commit;
現在,我們就來分析一下,如果只在 id=5 這一行加鎖,而其他行的不加鎖的話,會怎麼
樣。
下面先來看一下這個場景(注意:這是我假設的一個場景):
 
 
可以看到,session A 裏執行了三次查詢,分別是 Q1、Q2 和 Q3。它們的 SQL 語句相同,都是 select * from t where d=5 for update。這個語句的意思你應該很清楚了,查所有 d=5 的行,而且使用的是當前讀,並且加上寫鎖。現在,我們來看一下這三條 SQL語句,分別會返回什麼結果。
1. Q1 只返回 id=5 這一行;
2. 在 T2 時刻,session B 把 id=0 這一行的 d 值改成了 5,因此 T3 時刻 Q2 查出來的是id=0 和 id=5 這兩行;
3. 在 T4 時刻,session C 又插入一行(1,1,5),因此 T5 時刻 Q3 查出來的是 id=0、id=1 和 id=5 的這三行。
 
其中,Q3 讀到 id=1 這一行的現象,被稱爲“幻讀”。也就是說,幻讀指的是一個事務在前後兩次查詢同一個範圍的時候,後一次查詢看到了前一次查詢沒有看到的行。
 
這裏,我需要對“幻讀”做一個說明:
 
1. 在可重複讀隔離級別下,普通的查詢是快照讀,是不會看到別的事務插入的數據的。因此,幻讀在“當前讀”下才會出現。
2. 上面 session B 的修改結果,被 session A 之後的 select 語句用“當前讀”看到,不能稱爲幻讀。幻讀僅專指“新插入的行”。
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章