MySQL十種鎖,一篇文章帶你全解析

一燈架構 發表於 2022-06-27
MySQL

MySQL有兩個核心的知識點,索引和鎖。前幾篇文章已經詳細講解了MySQL索引實現機制,今天再一起學習一下MySQL的鎖。

1 為什麼要加鎖?

當多個事務併發操作同一批資料的時候,如果不加鎖,就無法保證事務的隔離性,最後導致資料錯亂。

加鎖是為了保證併發操作下資料的正確性。

2 鎖的分類有哪些?

按鎖的粒度可分為:表鎖、頁面鎖、行鎖、記錄鎖、間隙鎖、臨鍵鎖

按鎖的屬性可分為:共享鎖、排它鎖

按加鎖機制可分為:樂觀鎖、悲觀鎖

下面依次介紹一下這幾種鎖:

表鎖:

MyISAM和InnoDB引擎均支援表鎖。

優點:開銷小,加鎖快,不會出現死鎖。

缺點:鎖定力度大,發生鎖衝突概率高,併發度最低。

加鎖方式:

# 對user表加讀鎖
lock table user read;
# 同時對user表加讀鎖,對order表加寫鎖
lock tables user read, order write;

什麼情況下需要用到表鎖?

  1. 當需要更新表中的大部分資料
  2. 事務涉及到多張表,業務邏輯複雜,加表鎖可以避免死鎖。

頁面鎖:

優點:開銷和加鎖速度介於表鎖和行鎖之間。

缺點:會出現死鎖,鎖定粒度介於表鎖和行鎖之間,併發度一般。

目前只有BDB引擎支援頁面鎖,應用場景較少。

行鎖:

只有InnoDB引擎支援行鎖,另外鎖是加在索引上面的。

優點: 開銷大,加鎖慢;會出現死鎖。

缺點:鎖定粒度小,發生鎖衝突的概率低,併發度高。

另外記錄鎖、間隙鎖、臨鍵鎖均屬於行鎖。

記錄鎖(Record Locks):

即對某條記錄加鎖。

# 對id=1的使用者加鎖
update user set age=age+1 where id=1;

間隙鎖(Gap Locks):

即對某個範圍加鎖,但是不包含範圍的臨界資料。

# 對id大於1並且小於10的使用者加鎖
update user set age=age+1 where id>1 and id<10;

上面SQL的加鎖範圍是(1,10)。

臨鍵鎖(Next-Key Locks):

由記錄鎖和間隙鎖組成,既包含記錄本身又包含範圍,左開右閉區間。

# 對id大於1並且小於等於10的使用者加鎖
update user set age=age+1 where id>1 and id<=10;

共享鎖(又稱讀鎖、S鎖):

作用:防止其他事務修改當前資料。

加鎖方式:

在select語句末尾加上lock in share mode關鍵字。

# 對id=1的使用者加讀鎖
select * from user where id=1 lock in share mode;

排他鎖(又稱寫鎖、X鎖):

作用:防止其他事務讀取或者更新當前資料。

加鎖方式:

在select語句末尾加上for update關鍵字。

# 對id=1的使用者加寫鎖
select * from user where id=1 for update;

樂觀鎖:

總是假設別人不會修改當前資料,所以每次讀取資料的時候都不會加鎖,只是在更新資料的時候通過version判斷別人是否修改過資料,Java的atomic包下的類就是使用樂觀鎖(CAS)實現的。

適用於讀多寫少的場景。

加鎖方式:

  1. 讀取version

    select id,name,age,version from user id=1;
    
  2. 更新資料,判斷version是否修改過。

    update user set age=age+1 where id=1 and version=1;
    

悲觀鎖:

總是假設別人會修改當前資料,所以每次讀取的時候,總是加鎖。

適用於寫多讀少的場景。

加鎖方式:

# 加讀鎖
select * from user where id=1 lock in share mode;
# 加寫鎖
select * from user where id=1 for update;

本文知識點總結:

MySQL十種鎖,一篇文章帶你全解析

文章持續更新,可以微信搜一搜「 一燈架構 」第一時間閱讀更多技術乾貨。