資料庫篇:mysql鎖詳解

潛行前行發表於2022-03-29

前言

sql事務的執行,如果需要鎖定資料進行更新操作,則必定離不開鎖

  • 共享鎖和排他鎖
  • 表鎖
  • 行鎖 Record Lock
  • 間隙鎖 Gap Lock
  • 行鎖+間隙鎖 Next-Key Lock
  • 加鎖場景(加鎖sql)

關注公眾號,一起交流,微信搜一搜: 潛行前行

1 共享鎖和排他鎖

  • 排他鎖(X鎖),當前事務給記錄上鎖後(insert update delete),可以進行讀寫,其他事務不可以加任何鎖
  • 共享鎖(S鎖),是指當前事務給一條記錄上鎖後,其他事務也可以給當前記錄加共享鎖。共享鎖只用於鎖定讀,如需要更新資料,是不允許的

2 表鎖

針對資料庫表的鎖,又稱為表

  • 開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低
  • MySQL表級鎖有兩種模式:表共享鎖(Table Read Lock)和表獨佔寫鎖(Table Write Lock)
  • myisam,memory,merge 儲存引擎只支援表鎖

表級別的 AUTO_INC 鎖

在為表某列新增 AUTO_INCREDMENT 屬性,之後插入資料時可以不指定該欄位,系統會自動為它賦值,此時獲取自增值是需要 AUTO_INC 鎖鎖定的

3 行鎖 Record Lock

  • innodb 既支援表鎖也支援行鎖,行鎖是針對一行記錄的鎖
  • 行鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高
  • innodb 執行 select update delete insert 語句是不會為表加 S 鎖和 X 鎖,因為表鎖力度大,容易阻塞
  • 單條索引記錄上加鎖,record lock鎖住的永遠是索引,而非記錄本身,即使該表上沒有任何索引,那麼innodb會在後臺建立一個隱藏的聚集主鍵索引,那麼鎖住的就是這個隱藏的聚集主鍵索引。所以說當一條sql沒有走任何索引時,那麼將會在每一條聚集索引後面加X鎖

何為意向鎖

如果存在行鎖的情況,想給表加鎖,怎麼辦?遍歷檢視錶有沒有行鎖,太浪費時間了。此時意向鎖登場啦

  • 意向共享鎖(IS鎖):當事務給某行記錄增加 S 鎖時,同時給表加個 IS 鎖
  • 意向獨佔鎖(IX鎖):當事務給某行記錄增加 X 鎖時,同時給表加個 IX 鎖
    image.png
  • 有了意向鎖,則不需要遍歷資料也可以直接判斷是否可以給表加鎖

4 間隙鎖 Gap Lock

mysql 在 repeatable read 隔離級別解決幻讀的,有兩種實現方式。一是靠 MVCC 方案解決;二是加鎖方案解決。然而在事務加鎖時,記錄是不存在的,是無法加行鎖的。則需要靠間隙鎖(gap lock)實現
image.png

  • 例如給 id=10 記錄加 gap 鎖,鎖住(5,10)區間。另一事務想插入 id=8 的記錄,會先定位到 id=10 的記錄,然後發現存在一個 gap 鎖,則阻塞直到 第一個事務將 gap 鎖釋放掉,才可以在(5,10)區間插入記錄
  • gap lock 僅僅是為了防止插入幻影記錄,並不會限制其他事務對記錄繼續加行鎖 或者 gap 鎖

5 行鎖+間隙鎖 Next-Key Lock

  • next-key鎖的本質是 record lock 加一個gap lock的結合體。它既能保護該記錄,又能阻止別的事務將新的記錄插入被保護記錄的前面間隙中

6 加鎖場景(repeatable read 隔離級別加鎖 sql,忽略二級索引的加鎖操作)

  • 快照讀:讀的是資料庫記錄的快照版本,sql 執行前和當前事務ID生成的最新資料
  • 當前讀:讀取已提交事務生成的資料,大於當前事務ID的已提交事務,其生成的資料也可以讀取

select from

  • 不加任何鎖,快照讀

select for update

  • 聚簇索引上加 X 鎖,當前讀

select lock in share mode

  • 聚簇索引上加行級 S 鎖,採用當前讀

insert、update 和 delete 語句的加鎖情況

  • insert 在可重複讀級別加的是 next-key lock
  • delete、update 是在聚簇索引記錄加上 X 鎖

歡迎指正文中錯誤

參考文章

  • mysql是怎樣執行的(書籍)

相關文章