1. 程式人生 > >【 58沈劍 架構師之路】各種SQL到底加了什麼鎖?

【 58沈劍 架構師之路】各種SQL到底加了什麼鎖?

有朋友留言:你TM講了這麼多,分了這麼多型別,又和事務隔離級別相關,又和索引相關,究竟能不能直接告訴我,一個SQL到底加了什麼鎖!?

 

我竟無言以對。

 

好吧,做過簡單梳理之後,今天嘗試著直接回答,儘量做到不重不漏,各種SQL語句究竟加了什麼鎖

 

一、普通select

(1)在讀未提交(Read Uncommitted),讀提交(Read Committed, RC),可重複讀(Repeated Read, RR)這三種事務隔離級別下,普通select使用快照讀(snpashot read),不加鎖,併發非常高;

 

(2)在序列化(Serializable)這種事務的隔離級別下,普通select會升級為select ... in share mode;

 

【快照讀】輔助閱讀:

InnoDB,併發如此之高的原因

 

【事務隔離級別】輔助閱讀:

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);

 

表中有三條記錄:

1, shenjian

2, zhangsan

3, 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語句的加鎖,對於分析多個事務之間的併發與互斥,以及事務死鎖,非常有幫助。

 

如果還沒有厭倦這個話題,後文分解。

畫外音:從閱讀量看,貌似InnoDB系列已經有點膩了?我估計,是底層東西對寫業務程式碼沒啥用?