InnoDB引擎的行鎖

InnoDB引擎特色簡述

  • 支持事務
  • 支持外鍵
  • 必需要有主鍵,聚焦索引
  • 不支持全文檢索
  • 使用行鎖

行鎖特色

  支持事務,加鎖開銷大,加鎖慢,會出現死鎖,鎖的粒度小,併發下等待鎖的機率較低,因此支持高併發。html

手動事務語法

手動測試行鎖須要首先關閉自動提交,每一個會話都須要關閉自動提交mysql

mysql> SHOW VARIABLES LIKE 'autocommit';    #查看
mysql> SET autocommit = 0;

 

中間執行SQLsql

最後執行完了須要進行提交session

mysql> COMMIT;

最佳實踐

步驟 Session1 Session2
1 能夠查詢innodb_lock表數據  能夠查詢innodb_lock表數據
2 能夠增刪改innodb_lock表數據 能夠查詢舊數據,增刪改innodb_lock表數據阻塞
3 commit commit同時阻塞的增刪改爲功
4 能夠增刪改innodb_lock表數據 增刪改innodb_lock表與Session1不一樣行數據也阻塞
5 commit commit同時阻塞的增刪改爲功
6 沒能獲取session2更新的數據 commit
7 能夠查詢innodb_lock表更新後數據  

 

 

 

 

 

 

 

 

這裏有幾個問題:併發

  • 這兩個session,誰先進行的增刪改,誰就先拿到鎖。可是在查詢的時候,若是session1進行了一次SELECT操做,而session2提交以後,session1再一次的SELECT是沒法獲取session2更新的值的,必須session1進行提交後才能夠更新數據。
  • 在第3步,session2會將session1更新的數據覆蓋掉
  • 在第4步,session2修改的與session1不一樣的行也會阻塞,在這裏其實session1的鎖是表鎖,只有用上索引以後才能變爲行鎖。

針對給表加索引,讓表鎖變行鎖的實踐

表名:innodb_lock高併發

 

步驟 Session1 Session2
1 CREATE INDEX idx_id ON innodb_lock(id);  
2 COMMIT;  
3 UPDATE innodb_lock SET color = 'pink' WHERE id = 1; UPDATE innodb_lock SET color = 'yellow' WHERE id = 2;
4 COMMIT; COMMIT;

 

 

 

 

 

在這裏兩個session能夠同時更新數據,實現行鎖。咱們能夠看出這個索引落在WHERE語句參數的ID上,假如沒有WHERE 條件而且沒有索引是否也可成功?測試

步驟 Session1 Session2
1 DROP INDEX idx_id ON innodb_lock;  
2 COMMIT;  
3 UPDATE innodb_lock SET color = 'red' WHERE id = 1; UPDATE innodb_lock SET color = 'black';
4 COMMIT; COMMIT;

 

 

 

 

 

在第3行session2發生阻塞,由於沒有索引則會發生阻塞。spa

 手動鎖定記錄

這種鎖方式也是MySQL實現悲觀鎖的方式3d

mysql> BEGIN;
mysql> SELECT ... FOR UPDATE;

在中間進行數據更新code

mysql> COMMIT;

最後進行提交。

最佳實踐

一、仍是innodb_lock這張表和數據,自動提交開啓的狀況和沒有索引的實踐手動鎖定記錄。

步驟 Session1 Session2
1 BEGIN;  
2 SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE;  UPDATE innodb_lock SET color = 'orange' WHERE id = 1; #阻塞
3 UPDATE innodb_lock SET color = 'pink' WHERE id = 1;  
4 COMMIT; #阻塞釋放,執行更新,數據被覆蓋爲orange

 

 

 

 

 

二、上一個測試兩個session修改的是同一條數據,若是修改不同的數據,是否還會發生阻塞

步驟 Session1 Session2
1 BEGIN;  
2 SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE;  UPDATE innodb_lock SET color = 'yellow' WHERE id = 2; #阻塞
3 UPDATE innodb_lock SET color = 'red' WHERE id = 1;  
4 COMMIT; #阻塞釋放,執行更新

 

 

 

 

 

三、這裏能夠看到session1對數據表進行了鎖表,那咱們給id加上索引是否就不會阻塞

步驟 Session1 Session2
1 CREATE INDEX idx_id ON innodb_lock(id);  
2 BEGIN;  
3 SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE;  UPDATE innodb_lock SET color = 'blue' WHERE id = 2; #未阻塞
4 UPDATE innodb_lock SET color = 'pink' WHERE id = 1;  
5 COMMIT;  

 

 

 

 

 

 

四、session2未發生阻塞,那麼假如鎖定的行與更新的行不是一個行那session2能更新哪行呢

步驟 Session1 Session2
1 BEGIN;  
2 SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE;  
3 UPDATE innodb_lock SET color = 'yellow' WHERE id = 2;  UPDATE innodb_lock SET color = 'red' WHERE id = 1;  #阻塞
4   UPDATE innodb_lock SET color = 'orange' WHERE id = 2;  #阻塞
5   UPDATE innodb_lock SET color = 'grey' WHERE id = 3;  #未阻塞
6 COMMIT;  

 

 

 

 

 

 

 

五、咱們發現id爲1和2的兩行都被鎖住了,若是這樣的話是否是說明只要是鎖定或更新的行都會被鎖

步驟 Session1 Session2
1 INSERT INTO innodb_lock VALUES(4, 'red'),(5, 'orange');  
1 BEGIN;  
2 SELECT * FROM innodb_lock WHERE id < 3 FOR UPDATE;  
3 UPDATE innodb_lock SET color = 'black' WHERE id > 3;  UPDATE innodb_lock SET color = 'black' WHERE id = 1;  #阻塞
4   UPDATE innodb_lock SET color = 'black' WHERE id = 2;  #阻塞
5   UPDATE innodb_lock SET color = 'black' WHERE id = 3;  #阻塞
6    UPDATE innodb_lock SET color = 'black' WHERE id = 4;  #阻塞
7   UPDATE innodb_lock SET color = 'black' WHERE id = 5;  #阻塞
8 COMMIT;  

 

 

 

 

 

 

 

 

 

 

六、不會吧,所有阻塞了,id爲3的數據明明沒在鎖住和更新的數據裏,這是爲何呢?咱們再試一組數據。

步驟 Session1 Session2
1 INSERT INTO innodb_lock VALUES(6, 'purple'),(7, 'white');  
2 BEGIN;  
3 SELECT * FROM innodb_lock WHERE id < 3 FOR UPDATE;  
4 UPDATE innodb_lock SET color = 'black' WHERE id > 5; UPDATE innodb_lock SET color = 'black' WHERE id = 2;  #阻塞
5   UPDATE innodb_lock SET color = 'black' WHERE id = 3;  #阻塞
6   UPDATE innodb_lock SET color = 'black' WHERE id = 4;  #未阻塞
7   UPDATE innodb_lock SET color = 'black' WHERE id = 5;  #未阻塞
8   UPDATE innodb_lock SET color = 'black' WHERE id = 6;  #阻塞
9   INSERT INTO innodb_lock VALUES(8, 'test');  #阻塞
10 COMMIT;  

 

 

 

 

 

 

 

 

 

 

我再添加兩條數據,我知道的顏色單詞就這些了,多一個也想不起來了。

我嘞個去,結果讓人匪夷所思,小於號是後媽養的嗎?爲何3就阻塞而5就不阻塞。

好吧,算你厲害,你們仍是記住這個結果吧。

這裏這種範圍的鎖定就是傳說中的間隙鎖,他有一種特色就是隻要在範圍以內的數據所有被鎖住,無論當前是否存在。

七、若是有兩張innodb的表,兩個session鎖住各一張表,而後再去更新對方的那張表會怎樣呢?

步驟 Session1 Session2
1 BEGIN;  BEGIN;
2 SELECT * FROM innodb_lock WHERE id = 1 FOR UPDATE;  SELECT * FROM innodb_test WHERE id = 1 FOR UPDATE;
3 UPDATE innodb_test SET color = 'pink' WHERE id = 1;  #阻塞 UPDATE innodb_lock SET color = 'pink' WHERE id = 1;  #阻塞
4 COMMIT;  

 

 

 

 

 

在第3行都發生了阻塞,而在Session2的第3行出現如下錯誤

這裏出現了傳說中的死鎖,就是兩個session吃着本身碗裏的還看着對方碗裏的,雙方還都是倔脾氣,就在這裏槓上了,誰也不服誰。

查看行鎖的信息

  • Innodb_row_lock_current_waits:當前正在等待的數量
  • Innodb_row_lock_time:從啓動到如今鎖定的總時長,單位ms
  • Innodb_row_lock_time_avg:鎖等待的平均時長,單位ms
  • Innodb_row_lock_time_max:等待鎖時間最長的一個時間,單位ms
  • Innodb_row_lock_waits:總共的等待次數

本文索引關鍵字:

間隙鎖:http://www.cnblogs.com/huanStephen/p/8076172.html#c_lock

悲觀鎖:http://www.cnblogs.com/huanStephen/p/8076172.html#p_lock

死鎖:http://www.cnblogs.com/huanStephen/p/8076172.html#d_lock

歡迎你們索引!

相關文章
相關標籤/搜索