mysql innodb RR級別到底有沒有解決幻讀?

先說概念性的東西

事務的四種隔離級別:

01:Read uncommitted(讀未提交):最低級別,任何情況都會發生。

02:Read Committed(讀已提交):可避免髒讀的發生。

03:Repeatable read(可重複讀):可避免髒讀、不可重複讀的發生。一般數據庫默認級別

04:Serializable(串行化):避免髒讀、不可重複讀,幻讀的發生。

 

髒讀:事務A讀取到了事物B更新的數據,然後B回滾

不可重複讀:事務A多次讀取同一數據,事務B在A讀取過程中修改了並提交,導致A多次讀取同一數據結果不一樣

幻讀:A操作數據庫的過程中B插入了一條記錄,當A執行完發現有一條記錄沒有處理,就像發生了幻覺。

不可重複讀側重於修改,幻讀側重於新增和刪除。

實驗準備數據:

CREATE TABLE `yunfei` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` int(11) DEFAULT NULL,
  `value` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_type` (`type`)
) ENGINE=InnoDB AUTO_INCREMENT DEFAULT CHARSET=utf8;


INSERT INTO `yunfei` (`id`, `type`, `value`) VALUES ('1', '1', 'aa');
INSERT INTO `yunfei` (`id`, `type`, `value`) VALUES ('2', '2', 'bb');
INSERT INTO `yunfei` (`id`, `type`, `value`) VALUES ('3', '3', 'cc');
INSERT INTO `yunfei` (`id`, `type`, `value`) VALUES ('4', '4', 'dd');
INSERT INTO `yunfei` (`id`, `type`, `value`) VALUES ('5', '7', 'ee');
INSERT INTO `yunfei` (`id`, `type`, `value`) VALUES ('6', '10', 'ff');

 

實驗A:

 

sessionA                               sessionB

begin;                                 begin;

select * from yunfei;        
id type value
1	1	aa
2	2	bb
3	3	cc
4	4	dd
5	7	ee
6	10	ff
                                        insert into yunfei(type,value) values ('9','ddddddd'); 
                                        commit;
select * from yunfei; 
id type value
1	1	aa
2	2	bb
3	3	cc
4	4	dd
5	7	ee
6	10	ff

insert into yunfei(type,value) values ('9','ddddddd'); 

[SQL]
[Err] 1062 - Duplicate entry '9' for key 'aa'

select * from yunfei; 
id type value
1	1	aa
2	2	bb
3	3	cc
4	4	dd
5	7	ee
6	10	ff

update yunfei set value='ddddddd' where type=9;

[SQL]
Affected rows: 0
Time: 0.000s

select * from yunfei; 
id type value
1	1	aa
2	2	bb
3	3	cc
4	4	dd
5	7	ee
6	10	ff
34	9	ddddddd


                          


 

實驗B

sessionA                                sessionB 
begin;                                 begin

select * from yunfei for update;        
id  type value
1	1	aa
2	2	bb
3	3	cc
4	4	dd
5	7	ee
6	10	ff
                                        insert into yunfei(type,value) values ('9','ddddddd'); 
                                        無法插入!會一直等待,直到session1 commit或rollback

                                        insert into yunfei(type,value) values ('11','ddddddd'); 
                                        無法插入!會一直等待,直到session1 commit或rollback


rollback;

begin;

select * from yunfei where 4<type<10 for update;   
id  type value
1	1	aa
2	2	bb
3	3	cc
4	4	dd
5	7	ee
6	10	ff
                                        insert into yunfei(type,value) values ('9','ddddddd'); 
                                        無法插入!會一直等待,直到session1 commit或rollback


                                        insert into yunfei(type,value) values ('11','ddddddd'); 
                                        [SQL]
                                        Affected rows: 1
                                        Time: 0.003s




                          

結論(自己實驗總結的,有錯誤請留言指正):

mysql innodb只在一定程度上避免了一些幻讀,但明沒有真正解決幻讀。

快照讀(普通select):

1:一個session永遠讀不到另外一個session提交的數據,避免了幻讀

2:一個session在執行過程中另外一個session插入了一條記錄並提交,那麼在當前session重複插入的時候唯一索引衝突,明明沒數據爲什麼衝突了?再次查詢並無多數據,但是衝突提醒變相的出現了幻讀。

3:一個session在執行過程中另外一個session插入了一條記錄並提交,那麼在當前session中修改另外一個session插入的數據提示會無數據受影響,但是再次查詢多了條數據?出現幻讀。

當前讀(select for update):

1·:一個session在當前讀過程中沒有用到索引,其他session無法插入數據,update鎖了全表,避免幻讀。

2::一個session在當前讀過程中用到了範圍索引,那麼其他session也會因爲行鎖(臨鍵鎖或者間隙鎖)的情況無法插入,避免幻讀。

 

mysql鎖的幾個實現原理:

意象鎖:

當行鎖存在時,表鎖無法拿到。意象鎖是一個標誌,當標誌位TRUE時表示已經有人拿到了意象鎖,在這個時候就無法鎖表了

臨鍵鎖(行鎖默認算法):

當type=range使用範圍查詢索引update時候有數據命中,InnoDB會鎖上Btree當前區間和下一個區間。

1、4、7、10 一共分爲5個區間,當範圍查詢>5且<9的時候理論上只有7會上鎖,實際上會鎖(4,7]和(7,10]兩個區間

間隙鎖:

臨鍵鎖查詢記錄不存在的時候,會退化成間隙鎖,鎖到了一個閉區間,只存在RR隔離級別

1、4、7、10 一共分爲5個區間,當範圍查詢>4且<6的時候沒有索引命中,這個時候會鎖上(4,7)區間。

記錄鎖:

當type=eq-ref 唯一性(主鍵、唯一)索引,條件爲精確匹配,退化成記錄鎖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章