1033 字
5 分钟
面试鸭-MySQL 中有哪些锁类型?
MySQL中有哪些锁类型?
可以从两个维度来分:粒度和模式
- 粒度
- 表锁:锁全表,锁住时不允许修改表的内容。
- 行锁
- 记录锁(record lock):锁住单一条记录,不允许修改删除插入这条记录。
- 间隙锁(gap lock):阻止插入数据到某个范围中。
- 临键锁(next-key lock):相当于记录锁+间隙锁。
- 模式
- 读锁(也叫S锁和共享锁):允许多个事务同时读取同一行数据,但是不允许任何事务写。
- 写锁(也叫X锁和独占锁):一个事务独占,其他事务不允许读也不允许写。
- 其它
- 意向锁:用来锁全表,标识里面有读锁或者写锁,这样就能快速知道是否有锁而不用遍历全部记录。
- 元数据锁(MDL):用于保护表结构,让DDL和DML不能同时跑。防止并发的 DDL 操作和 DML 操作冲突和保护元数据一致性
- 读锁:当一个事务需要读取元数据时就会获取读锁。
- 写锁:当一个事务需要修改元数据时就会获取写锁。
- 插入意向锁:标识接下来有插入的意向,用于等待某个间隙。
- Auto-inc Lock:一个特殊的表级锁,用于解决并发插入时,使用statement格式的binlog回放值会出现自增值顺序不正确递增的问题。配置:innodb_autoinc_lock_mode
- 0:只使用Auto-inc Lock,也就是在语句插入结束才释放锁,并发性能很差。
- 1:默认值,根据数量来决定使用的策略,如果数量确定且不是很多,使用互斥量来解决微小的并发。如果不知道数量,会使用0的策略。
- 2:MySQL 8.0+默认值,因为MySQL现在的binlog用的是Row格式,不受数据插入先后顺序影响,因此可以完全使用互斥量来解决并发时自增的问题,在新版官方直接把默认值换成了2,并发性能更好了。
问题
什么情况下会触发表锁而不是行锁?
- 查询没走索引时,InnoDB就会走全表扫描,就会锁全表。
- 手动指定锁全表的时候。 Lock tables
- 使用了DDL语句,因为锁操作表的,会自动锁上表。
两个事务都使用间隙锁锁住同一个间隙,会死锁吗?
看情况,两个事务都单独持有间隙锁的话不会,因为间隙锁不冲突目的都是防止插入。 但是如果两个事务同时持有对方要插入位置的间隙锁,就会出现死锁。 比如事务A持有(1,2),想插入(5,6)。事务B持有(5,6),想插入(1,2),两个事务都得在等对方释放锁才能插入,就会出现死锁。
为什么说间隙锁是可重复读级别持有的?
因为可重复读需要防止幻读,所以需要间隙锁来帮助。而读已提交级别不需要防止幻读问题,就不需要间隙锁,只需要保留记录锁,记录锁的范围比较小,不容易出现死锁,因此很多公司都选择读已提交级别。
线上加字段导致查询全部超时,原因是什么?
可能是因为存在长事务持有了读锁未释放,而Alter table需要持有写锁,于是就等待这个长事务的读锁释放,在这个时候MySQL的优先级是优先写锁的,于是接下来的查询全部都没办法持有读锁导致卡在ALTER TABLE的后面。 解决办法有两个:
- 先解决长事务再执行DDL
- 使用pt-online-schema-change这类工具实现无锁DDL(原理是创建一个新表 然后立即新增字段,接下来慢慢的把数据从老表复制过去,并且在这期间记录所有老表的增删改,自动的也一起同步过去,数据同步齐全之后,立马修改两张表的名字然后把老表删掉)
面试鸭-MySQL 中有哪些锁类型?
http://www.shineacz.top/posts/面试鸭-mysql-中有哪些锁类型/