ITPub博客

首页 > > > 别废话,各种SQL到底加了什么锁?

别废话,各种SQL到底加了什么锁?

作者:58沈剑 时间:2019-12-30 16:11:31 0 删除 编辑

这个月花了一些功夫写InnoDB:并发控制,MVCC,索引,锁... 


有朋友留言:你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插入。



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31556838/viewspace-3167657/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
58速运CTO,互联网架构技术专家,“架构师之路”公众号作者。曾任百度高级工程师,58同城技术委员会主席,高级架构师,58到家技术委员会主席,高级技术总监,目前主要负责58速运技术部。

注册时间:2018-09-30

  • 博文量
    420
  • 访问量
    82596