1. 程式人生 > >幻讀是什麼?幻讀有什麼問題

幻讀是什麼?幻讀有什麼問題

一: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;

這條語句會命中d=5這一行,對應主鍵是id =5 ,這一行會加一個寫鎖。 由於d 上沒有索引,這條語句查詢的時候會做全表掃描。但是 不滿足條件的5行記錄上會不會加鎖呢?

二:幻讀是什麼:

 

 查詢語句用的是當前讀,並且加上了些鎖。Q3讀到id = 1 這一行的現象稱為幻讀。

1.在可重複讀隔離級別下,普通查詢是快照讀,是不會看到別的事務插入的資料,幻讀在當前讀下才會出現。

2.sessionb 的修改結果被sessiona讀到,不能稱為幻讀,幻讀指的是行插入的行

 

 

 幻讀有什麼問題:

1.語義上的。

sessonA是要給d=5的加鎖。但是sessionB ,sessionC 都可以執行成功。sessionA只是給id = 5 加了鎖。

 

2 。破壞了資料一致性

這個一致性,不止是資料庫內部資料狀態在此刻的一致性,還包含了資料和日誌在邏輯上的一致性。

 

 

 

 update t set d=5 where id=0; /*(0,0,5)*/
update t set c=5 where id=0; /*(0,5,5)*/

insert into t values(1,1,5); /*(1,1,5)*/
update t set c=5 where id=1; /*(1,5,5)*/

update t set d=100 where d=5;/* 所有 d=5 的行,d 改成 100*/

 

 

 

 insert into t values(1,1,5); /*(1,1,5)*/
update t set c=5 where id=1; /*(1,5,5)*/

update t set d=100 where d=5;/* 所有 d=5 的行,d 改成 100*/

update t set d=5 where id=0; /*(0,0,5)*/
update t set c=5 where id=0; /*(0,5,5)*/

 

 上邊把表的所有資料都加了鎖,但是還是插入了資料 。

 

如何解決幻讀?

新插入的語句是更新的記錄之間的間隙。為了解決這個問題,引入了間隙鎖。

產生 了七個間隙 。

select * from t where d= 5 for update;,不止給6個記錄加上了行鎖。同時還加了7個間隙鎖。這樣就確保無法插入新的記錄。

跟間隙鎖存在衝突關係的是往這個間隙中插入一個記錄,這個操作。間隙鎖之間都不存在衝突關係。

 

 

這倆條語句都加了 (5,10)這個間隙鎖,但是不衝突,不會吧sessionB阻塞住。

select * from t for update 是把整個表的所有記錄鎖起來。就形成了7個next-key-lock.

 但是也會出現問題。就是會發生死鎖;

 

 

 可能會引出併發讀。