MySQL有兩個核心的知識點,索引和鎖。前幾篇文章已經詳細講解了MySQL索引實現機制,今天再一起學習一下MySQL的鎖。
1 為什麼要加鎖?
當多個事務併發操作同一批資料的時候,如果不加鎖,就無法保證事務的隔離性,最後導致資料錯亂。
加鎖是為了保證併發操作下資料的正確性。
2 鎖的分類有哪些?
按鎖的粒度可分為:表鎖、頁面鎖、行鎖、記錄鎖、間隙鎖、臨鍵鎖
按鎖的屬性可分為:共享鎖、排它鎖
按加鎖機制可分為:樂觀鎖、悲觀鎖
下面依次介紹一下這幾種鎖:
表鎖:
MyISAM和InnoDB引擎均支援表鎖。
優點:開銷小,加鎖快,不會出現死鎖。
缺點:鎖定力度大,發生鎖衝突概率高,併發度最低。
加鎖方式:
# 對user表加讀鎖
lock table user read;
# 同時對user表加讀鎖,對order表加寫鎖
lock tables user read, order write;
什麼情況下需要用到表鎖?
- 當需要更新表中的大部分資料
- 事務涉及到多張表,業務邏輯複雜,加表鎖可以避免死鎖。
頁面鎖:
優點:開銷和加鎖速度介於表鎖和行鎖之間。
缺點:會出現死鎖,鎖定粒度介於表鎖和行鎖之間,併發度一般。
目前只有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)實現的。
適用於讀多寫少的場景。
加鎖方式:
-
讀取version
select id,name,age,version from user id=1;
-
更新資料,判斷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;
本文知識點總結:
文章持續更新,可以微信搜一搜「 一燈架構 」第一時間閱讀更多技術乾貨。