有朋友留言:你TM講了這麼多,鎖分了這麼多類型,又和事務隔離級別相關,又和索引相關,究竟能不能直接告訴我,一個SQL到底加了什麼鎖!?併發
我竟無言以對。spa
好吧,作過簡單梳理以後,今天嘗試着直接回答,儘可能作到不重不漏,各類SQL語句究竟加了什麼鎖。3d
1、普通select索引
(1)在讀未提交(Read Uncommitted),讀提交(Read Committed, RC),可重複讀(Repeated Read, RR)這三種事務隔離級別下,普通select使用快照讀(snpashot read),不加鎖,併發很是高;事務
(2)在串行化(Serializable)這種事務的隔離級別下,普通select會升級爲select ... in share mode;get
【快照讀】輔助閱讀:it
《InnoDB,併發如此之高的緣由》io
【事務隔離級別】輔助閱讀:date
《InnoDB,巧妙的實現四種事務的隔離級別》select
2、加鎖select
加鎖select主要是指:
select ... for update
select ... in share mode
(1)若是,在惟一索引(unique index)上使用惟一的查詢條件(unique search condition),會使用記錄鎖(record lock),而不會封鎖記錄之間的間隔,即不會使用間隙鎖(gap lock)與臨鍵鎖(next-key lock);
【記錄鎖,間隙鎖,臨鍵鎖】輔助閱讀:
舉個栗子,假設有InnoDB表:
t(id PK, name);
表中有三條記錄:
1, shenjian
2, zhangsan
3, lisi
SQL語句:
select * from t where id=1 for update;
只會封鎖記錄,而不會封鎖區間。
(2)其餘的查詢條件和索引條件,InnoDB會封鎖被掃描的索引範圍,並使用間隙鎖與臨鍵鎖,避免索引範圍區間插入記錄;
3、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的值,檢索普通索引本質上要二次掃描彙集索引。
【索引底層實現】輔助閱讀:
【彙集索引與普通索引的實現差別】輔助閱讀:
4、insert
一樣是寫操做,insert和update與delete不一樣,它會用排它鎖封鎖被插入的索引記錄,而不會封鎖記錄以前的範圍。
同時,會在插入區間加插入意向鎖(insert intention lock),但這個並不會真正封鎖區間,也不會阻止相同區間的不一樣KEY插入。
【插入意向鎖】輔助閱讀:
瞭解不一樣SQL語句的加鎖,對於分析多個事務之間的併發與互斥,以及事務死鎖,很是有幫助。
若是尚未厭倦這個話題,後文分解。
畫外音:從閱讀量看,貌似InnoDB系列已經有點膩了?我估計,是底層東西對寫業務代碼沒啥用?