Mysql InnoDB 行鎖和表鎖介紹
阿新 • • 發佈:2019-05-24
mysql 的 InnoDB引擎支援行鎖,與Oracle不同,mysql的行鎖是通過索引載入的,即是行鎖是加在索引響應的行上的,要是對應的SQL語句沒有走索引,則會全表掃描,行鎖則無法實現,取而代之的是表鎖
先介紹幾個名詞
表鎖:不會出現死鎖,發生鎖衝突機率高,併發低
行鎖:會出現死鎖,發生鎖衝突機率低,併發高
鎖衝突:例如說事務A將某幾行上鎖後,事務B又對其上鎖,鎖不能共存否則會出現鎖衝突。(但是共享鎖可以共存,共享鎖和排它鎖不能共存,排它鎖和排他鎖也不可以)
死鎖:例如說兩個事務,事務A鎖住了1~5行,同時事務B鎖住了6~10行,此時事務A請求鎖住6~10行,就會阻塞直到事務B施放6~10行的鎖,而隨後事務B又請求鎖住1~5行,事務B也阻塞直到事務A釋放1~5行的鎖。死鎖發生時,會產生Deadlock錯誤。鎖是對錶操作的,所以自然鎖住全表的表鎖就不會出現死鎖。
行鎖的型別
共享鎖又稱:讀鎖。當一個事務對某幾行上讀鎖時,允許其他事務對這幾行進行讀操作,但不允許其進行寫操作,也不允許其他事務給這幾行上排它鎖,但允許上讀鎖。
排它鎖又稱:寫鎖。當一個事務對某幾個上寫鎖時,不允許其他事務寫,但允許讀。更不允許其他事務給這幾行上任何鎖。包括寫鎖。
共享鎖的寫法:lock in share mode
select * from test where math>60 lock in share mode;
排它鎖的寫法:for update
select * from test where math >60 for update;
行鎖的實現
注意幾點
1.行鎖必須有索引才能實現,否則會自動鎖全表
2.兩個事務不能鎖同一個索引
事務A先執行:
select * from test where math>60 for update;
事務B再執行:
select * from test where math<60 for update;
這樣的話,事務B是會阻塞的。如果事務B把 math索引換成其他索引就不會阻塞,
但注意,換成其他索引鎖住的行不能和math索引鎖住的行有重複。
行鎖示例
由於InnoDB預設是Row-Level Lock,所以只有「明確」的指定主鍵,MySQL才會執行Row lock (只鎖住被選取的資料例) ,否則MySQL將會執行Table Lock (將整個資料表單給鎖住)。
舉個例子:
假設有個表單products ,裡面有id跟name二個欄位,id是主鍵。
例1: (明確指定主鍵,並且查詢有資料,row lock)
SELECT * FROM products WHERE id='3' FOR UPDATE;
SELECT * FROM products WHERE id='3' and type=1 FOR UPDATE;
例2: (明確指定主鍵,若查詢無資料,無lock)
SELECT * FROM products WHERE id='-1' FOR UPDATE;
例2: (無主鍵,table lock)
SELECT * FROM products WHERE name='Mouse' FOR UPDATE;
例3: (主鍵不明確,table lock)
SELECT * FROM products WHERE id<>'3' FOR UPDATE;
例4: (主鍵不明確,table lock)
SELECT * FROM products WHERE id LIKE '3' FOR UPDATE;
注1: FOR UPDATE僅適用於InnoDB,且必須在(BEGIN/COMMIT)中才能生效