支持事務,加鎖開銷大,加鎖慢,會出現死鎖,鎖的粒度小,併發下等待鎖的機率較低,因此支持高併發。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表更新後數據 |
這裏有幾個問題:併發
表名: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吃着本身碗裏的還看着對方碗裏的,雙方還都是倔脾氣,就在這裏槓上了,誰也不服誰。
本文索引關鍵字:
間隙鎖: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
歡迎你們索引!