有朋友留言:你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系列已经有点腻了?我估计,是底层东西对写业务代码没啥用?