3. 一条SQL是如何加锁的呢?介绍完InnoDB的七种锁后,我们来看下一条SQL是如何加锁的哈,可以分9种情况进行:
- 组合一:查询条件是主键,RC隔离级别
- 组合二:查询条件是唯一索引,RC隔离级别
- 组合三:查询条件是普通索引,RC隔离级别
- 组合四:查询条件上没有索引,RC隔离级别
- 组合五:查询条件是主键,RR隔离级别
- 组合六:查询条件是唯一索引,RR隔离级别
- 组合七:查询条件是普通索引,RR隔离级别
- 组合八:查询条件上没有索引,RR隔离级别
- 组合九:Serializable隔离级别
我们搞个简单的表,初始化几条数据:
create table t1 (id int,name varchar(16),primary key ( id));insert into t1 values(1,'a'),(3,'c'),(6,'b'),(9,'a'),(10,'d');假设给定SQL:delete from t1 where id = 6;,id是主键 。在RC隔离级别下,只需要将主键上id = 6的记录,加上X锁即可 。
文章插图
我们来验证一下吧,先开启事务会话A,先执行以下操作:
begin;//删除id=6的这条记录delete from t1 where id = 6;接着开启事务会话Bbegin;update t1 set name='b1' where id =6;//发现这个阻塞等待,最后超时释放锁了验证流程图如下:
文章插图
事务会话B对id=6的记录执行更新时,发现阻塞了,打开看下加了什么锁,发现是因为id=6这一行加了一个X型的记录锁

文章插图
如果我们事务B不是对id=6执行更新,而是其他记录的话,是可以顺利执行的,如下:

文章插图
结论就是,在RC(读已提交) 的隔离级别下,对查询条件是主键id的场景,会加一个排他锁(X锁),或者说加一个X型的记录锁 。
3.2 查询条件是唯一索引+RC隔离级别如果查询条件id,只是一个唯一索引呢?那在RC(读提交隔离级别下),又加了什么锁呢?我们搞个新的表,初始化几条数据:
create table t2 (name varchar(16),id int,primary key (name),unique key(id));insert into t2 values('a',1),('c',3),('b',6),('d',9);id是唯一索引,name是主键的场景下,我们给定SQL:delete from t2 where id = 6; 。在RC隔离级别下,SQL需要加两个X锁,一个对应于id 唯一索引上的id = 6的记录,另一把锁对应于聚簇索引上的[name=’b’,id=6]的记录 。
文章插图
为什么主键索引上的记录也要加锁呢?
如果并发的一个SQL,是通过主键索引来更新:update t2 set id = 666 where name = 'b';此时,如果delete语句没有将主键索引上的记录加锁,那么并发的update就会感知不到delete语句的存在,违背了同一记录上的更新/删除需要串行执行的约束 。3.3 查询条件是普通索引 + RC隔离级别如果查询条件是普通的二级索引,在RC(读提交隔离级别下),又加了什么锁呢?
若id列是普通索引,那么对应的所有满足SQL查询条件的记录,都会加上锁 。同时,这些记录对应主键索引,也会上锁 。我们初始化下表结构和数据
create table t3 (name varchar(16),id int,primary key (name),key(id));insert into t3 values('a',1),('c',3),('b',6),('e',6),('d',9);加锁示意图如下:
文章插图
我们来验证一下,先开启事务会话A,先执行以下操作:
begin;//删除id=6的这条记录delete from t3 where id = 6;接着开启事务会话Bbegin;update t3 set id=7 where name ='e';//发现这个阻塞等待,最后超时释放锁了实践流程如下:
文章插图
事务B为什么会阻塞等待超时,是因为事务A的delete语句确实有加主键索引的X锁
推荐阅读
- C语言入门算法丨冒泡排序算法详解!绝不摆烂
- 适合中国家庭的国产两厢推荐
- 如何把红茶泡好喝,咖啡红茶怎么泡
- 职业教育|职业教育想要振兴,需要改变两大关键因素
- 滇红茶耐泡,凤庆滇红茶泡法
- 卧室有两个窗户对风水有利吗?
- 卧室有两个门对我们有什么影响
- 两个动作看透你 准确率达99%!
- Windows操作系统|Win11大更新就绪:微软详解重要新功能 CPU效率暴增、全新任务管理器
- 脂肪怎么排出,教你两招懒人方法
