MySQL中的表鎖、行鎖、間隙鎖以及死鎖

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;

若兩個事務同時執行到第二個語句,就會產生相互等待行鎖的情況,造成死鎖!

間隙鎖也可能產生死鎖

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