別廢話,各種SQL到底加了什么鎖?
有朋友留言,問能不能花2分鐘講講,MySQL的各類SQL語句,究竟加了什么鎖?
額,MySQL加的鎖,和事務隔離級別相關,又和索引相關,嘗試花2分鐘講講看。
畫外音:這2分鐘需要的輔助知識,都已經附帶了鏈接,貼心吧!
第一類,普通select加什么鎖?
(1)在讀未提交(Read Uncommitted),讀提交(Read Committed, RC),可重復讀(Repeated Read, RR)這三種事務隔離級別下,普通select使用快照讀(snpashot read),不加鎖,并發非常高;
(2)在串行化(Serializable)這種事務的隔離級別下,普通select會升級為select ... in share mode;
【快照讀】輔助閱讀:《??InnoDB,并發如此之高的原因??》
第二類,加鎖select加什么鎖?
加鎖select主要是指:
- select ... for update
- select ... in share mode
(1)如果,在唯一索引(unique index)上使用唯一的查詢條件(unique search condition),會使用記錄鎖(record lock),而不會封鎖記錄之間的間隔,即不會使用間隙鎖(gap lock)與臨鍵鎖(next-key lock);
【記錄鎖,間隙鎖,臨鍵鎖】輔助閱讀:《??InnoDB里的七種鎖??》
舉個栗子,假設有InnoDB表:
t(id PK, name);
表中有三條記錄:
- shenjian
- zhangsan
- lisi
SQL語句:
select * from t where id=1 for update;
只會封鎖記錄,而不會封鎖區間。
(2)其他的查詢條件和索引條件,InnoDB會封鎖被掃描的索引范圍,并使用間隙鎖與臨鍵鎖,避免索引范圍區間插入記錄;
第三類,update與delete加什么鎖?
(1)和加鎖select類似,如果在唯一索引上使用唯一的查詢條件來update/delete,例如:update t set name=xxx where id=1;也只加記錄鎖;
(2)否則,符合查詢條件的索引記錄之前,都會加排他臨鍵鎖(exclusive next-key lock),來封鎖索引記錄與之前的區間;
(3)尤其需要特殊說明的是,如果update的是聚集索引(clustered index)記錄,則對應的普通索引(secondary index)記錄也會被隱式加鎖,這是由InnoDB索引的實現機制決定的:普通索引存儲PK的值,檢索普通索引本質上要二次掃描聚集索引。
【索引底層實現】輔助閱讀:《??索引,底層是如何實現的???》
【聚集索引與普通索引的實現差異】輔助閱讀:《??InnoDB,聚集索引與普通索引有什么不同???》
第四類,insert加什么鎖?
同樣是寫操作,insert和update與delete不同,它會用排它鎖封鎖被插入的索引記錄,而不會封鎖記錄之前的范圍。
同時,會在插入區間加插入意向鎖(insert intention lock),但這個并不會真正封鎖區間,也不會阻止相同區間的不同KEY插入。
【插入意向鎖】輔助閱讀:《??InnoDB里的七種鎖??》
了解不同SQL語句的加鎖,對于分析多個事務之間的并發與互斥,以及事務死鎖,非常有幫助。
畫外音:文章的參考資料為MySQL官網,以及樓主對MySQL的理解,版本基于5.6,歡迎探討。
希望這2分鐘,大家有收獲。
來源鏈接:
http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651969353&idx=1&sn=9ded4fe3fcfc9e3daf1ce52054671b4a&chksm=bd2d62958a5aeb835405358634ffea69936a6dd3941dd2a338401661c77393838879c043db69&mpshare=1&scene=23&srcid=0118Za6sAKYOr1w7CpQHHEMB&sharer_sharetime=1642517052262&sharer_shareid=9603544ecd5d7f3dc66603ae089636f4#rd