最近我根据上述的技术体系图搜集了几十套腾讯、头条、阿里、美团等公司21年的面试题,把技术点整理成了视频(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分
由于表级锁一次会将整个表锁定,所以可以很好的避免死锁问题。当然,锁的粒度大所带来最大的负面影响就是出现锁资源争用的概率也会最高,导致并发率大打折扣。
而所谓 “行锁(Row Lock)”,也称为记录锁,顾名思义,就是锁住某一行(某条记录 row)。需要的注意的是,MySQL 服务器层并没有实现行锁机制,行级锁只在存储引擎层实现 !!!
读锁和写锁
首先说明一点,对于 InnoDB 引擎来说,读锁和写锁可以加在表上,也可以加在行上。
对于并发读和并发写的问题,可以通过实现一个由两种类型的锁组成的锁系统来解决。这两种类型的锁通常被称为 共享锁(Shared Lock,S Lock) 和 排他锁(Exclusive Lock,X Lock),也叫 读锁(readlock) 和 写锁(write lock):
-
共享锁 / 读锁:允许事务读(
select
)数据 -
排他锁 / 写锁:允许事务删除(
delete
)或更新(update
)数据
读锁是共享的,或者说是相互不阻塞的。多个事务在同一时刻可以同时读取同一个资源,而互不干扰。写锁是排他的,也就是说一个写锁会阻塞其他的读锁和写锁,这样就能确保在给定的时间里,只有一个事务能执行写入,并防止其他用户读取正在写入的同一资源。
用行级读写锁来举个例子吧:如果一个事务 T1 已经获得了某个行 r 的读锁,那么此时另外的一个事务 T2 是可以去获得这个行 r 的读锁的,因为读取操作并没有改变行 r 的数据;但是,如果某个事务 T3 想获得行 r 的写锁,则它其必须等待事务 T1、T2 释放掉行 r 上的读锁才行。
兼容关系如下表(兼容是指对同一张表或记录的锁的兼容性情况):
|
| X 锁 | S 锁 |
| — | — | — |
| X 锁 | 不兼容 | 不兼容 |
| S 锁 | 不兼容 | 兼容 |
从上表可以看出,只有共享锁和共享锁是兼容的,而排他锁和谁都是不兼容的。
意向锁
InnoDB 存储引擎支持 多粒度(granular)锁定,就是说允许事务在行级上的锁和表级上的锁同时存在。
那么为了实现行锁和表锁并存,InnoDB 存储引擎就设计出了 意向锁(Intention Lock) 这个东西:
Intention locks are table-level locks that indicate which type of lock (shared or exclusive) a transaction requires later for a row in a table.
很好理解:意向锁是一个表级锁,其作用就是指明接下来的事务将会用到哪种锁。
有两种意向锁:
-
意向共享锁(IS Lock):当事务想要获得一张表中某几行的共享锁行级锁)时,InnoDB 存储引擎会自动地先获取该表的意向共享锁(表级锁)
-
意向排他锁(IX Lock):当事务想要获得一张表中某几行的排他锁(行级锁)时,InnoDB 存储引擎会自动地先获取该表的意向排他锁(表级锁)
各位其实可以直接把 ”意向“ 翻译成 ”想要“,想要共享锁、想要排他锁,你就会发现原来就这东西啊(滑稽)。
意向锁之间是相互兼容的:
|
| IS 锁 | IX 锁 |
| — | — | — |
| IS 锁 | 兼容 | 兼容 |
| IX 锁 | 兼容 | 兼容 |
但是与表级读写锁之间大部分都是不兼容的:
|
| X 锁 | S 锁 |
| — | — | — |
| IS 锁 | 不兼容 | 兼容 |
| IX 锁 | 不兼容 | 不兼容 |
注意,这里强调一点:上表中的读写锁指的是表级锁,意向锁不会与行级的读写锁互斥!!!
来理解一下为什么说意向锁不会与行级的读写锁互斥。举个例子,事务 T1、事务 T2、事务 T3 分别想对某张表中的记录行 r1、r2、r3 进行修改,很普通的并发场景对吧,这三个事务之间并不会发生干扰,所以是可以正常执行的。
这三个事务都会先对这张表加意向写锁,因为意向锁之间是兼容的嘛,所以这一步没有任何问题。那如果意向锁和行级读写锁互斥的话,岂不是这三个事务都没法再执行下去了,对吧。
OK,看到这里,我们来思考两个问题:
1)为什么没有意向锁的话,表锁和行锁不能共存?
2)意向锁是如何让表锁和行锁共存的?
首先来看第一个问题,假设行锁和表锁能共存,举个例子:事务 T1 锁住表中的某一行(行级写锁),事务 T2 锁住整个表(表级写锁)。
问题很明显,既然事务 T1 锁住了某一行,那么其他事务就不可能修改这一行。这与 ”事务 T2 锁住整个表就能修改表中的任意一行“ 形成了冲突。所以,没有意向锁的时候,行锁与表锁是无法共存的。
再来看第二个问题,有了意向锁之后,事务 T1 在申请行级写锁之前,MySQL 会先自动给事务 T1 申请这张表的意向排他锁,当表上有意向排他锁时其他事务申请表级写锁会被阻塞,也即事务 T2 申请这张表的写锁就会失败。
如何加锁
在说加锁之前,我们有必要了解下解锁机制。对于 InnoDB 来说,随时都可以加锁,但是并非随时都可以解锁。具体来说,InnoDB 采用的是两阶段锁定协议(two-phase locking protocol):即在事务执行过程中,随时都可以执行加锁操作,但是只有在事务执行 COMMIT 或者 ROLLBACK 的时候才会释放锁,并且所有的锁是在同一时刻被释放。
说完了解锁机制,再来讲讲加锁机制。
最后
无论是哪家公司,都很重视基础,大厂更加重视技术的深度和广度,面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。
针对以上面试技术点,我在这里也做一些分享,希望能更好的帮助到大家。