1 Mysql鎖機制
- 表鎖:偏性MyISAM,開銷小加鎖塊,鎖定力度大,鎖衝突的概率最高;
- 行鎖:偏性InnoDB,開銷大但鎖衝突概率小;
- 間隙鎖:在可重複讀的隔離級別中存在,用於預防幻讀的出現。
1.1 MyISAM表鎖
當執行select語句時,默認對錶執行表鎖,當執行修改操作時,默認加寫鎖;
當一個連接獲取一張表讀鎖時,其他連接和該連接都不能修改該表,且該連接不能讀其他表;
當一個連接對錶加上寫鎖時,該連接可以讀寫;其他連接不能讀寫;
讀鎖會阻塞寫,寫鎖會阻塞讀寫;
表鎖適合做讀爲主的數據庫;
1.2 InnoDB行鎖
行鎖特點:開銷大,加鎖慢;可能出現死鎖;鎖衝突概率小,併發高;
併發事務帶來的問題:
- 丟失更新:兩個事務同時修改同一個數據,最後的事務修改會覆蓋之前的修改;
- 髒讀:讀取了未提交的事務
- 不可重複讀:在一個事務中,未提交之前看不到其他事務的修改,即使其他事務提交
- 幻讀:兩個查詢數據發現行數多了或者少了(其他事務插入了數據)
針對併發事務的問題,有四個隔離級別
- 未提交讀:最低的隔離級別,未提交的事務對其他事務可見
- 提交讀:未提交的事務對其他事務不可見
- 可重複讀(默認):同一個事務讀取的數據一致。
- 可串行化:解決所有問題
set autocommit=0; # 關閉自動提交
commit; #手動提交
InnoDB中默認支持的是行鎖,行鎖的特點:
- 事務1獲取一個行鎖,若執行寫操作(加寫鎖),其他事務不能對該行進行寫操作;
- 事務1獲取一個行鎖,若執行讀操作(讀鎖),其他事務可以對該行讀寫,但是對事務1不可見
**行鎖升級爲表鎖:**索引失效時行鎖升級爲表鎖;
1.3 間隙鎖
間隙鎖發生在可重複讀的隔離級別中,如若是提交讀隔離級別,是不存在間隙鎖的。
什麼是間隙鎖?
間隙鎖就是將鎖加在了不存在的空閒空間,防止其他事務去插入數據造成幻讀。
間隙鎖什麼時候加?
數據庫使用可重複讀隔離級別時,當開啓一個事務後,使用select ......where ... for update
或update/insert/delete語句時會加間隙鎖。**注意:正常的select ... where ...
語句不會造成間隙鎖,**因爲這樣是讀取快照版本而不是最新版本,不會有間隙鎖產生。
相同的,間隙鎖鎖住的行不影響其他事務讀取快照版本!
間隙鎖怎麼加?
談間隙鎖時必須談索引!!不同索引處理不同!!以下結論在MySQL5.7下實驗得出,實驗可能有不完善的情況導致結論不正確,歡迎指出。
當a無索引的時候
where a=1
時:會將所有行加間隙鎖where a>5
時:會鎖所有行where a<5
時:會鎖所有行
當a是唯一索引/主鍵索引時
where a=1
時:只鎖住a=1的左右間隙行。where a>5
時:會鎖住a>5的行。 由於是唯一索引,查詢操作不會因爲間隙鎖阻塞。where a<5
時:會鎖a<5的行。由於是唯一索引,查詢操作不會因爲間隙鎖阻塞。where a>5 and a<10
時:鎖全部行?a=1的行也被鎖?
當a是普通索引時
where a=1
時:只鎖住a=1的左右間隙行。where a>5
時:會鎖住所有行。where a<5
時:會鎖住所有行。where a>5 and a<10
時:鎖全部行。
優化總結:
- 儘可能讓所有數據檢索能通過索引完成,避免無索引行鎖升級爲表鎖
- 儘量減少鎖的範圍
- 儘可能控制事務大小,減少鎖定資源的數量和時間長度
1.4 死鎖
當數據庫兩個或多個事務在循環等待對方鎖資源時也會發生死鎖。
行鎖產生的死鎖:
# 事務一
update .... where id=1;
update .... where id=5;
# 事務二
update .... where id=5;
update .... where id=1;
若兩個事務同時執行到第二個語句,就會產生相互等待行鎖的情況,造成死鎖!
間隙鎖也可能產生死鎖