总结 MySQL 中的锁
Contents
众所周知,mysql 中有很多种锁的概念,如行锁、乐观锁、排它锁等等,本文对此进行归纳。
锁的类型
加锁类型的不同,表现在对竞争资源的处理有不同的处理思想。
假设有这样的场景,A、B 两个用户要同时将机票价格从 2 元改成 6、3 元。
乐观锁
取数据时,假定别人不会修改该数据,因此只会对数据做简单的校验,并不对数据上锁。
但如果有大量进程修改某行数据,就会导致大部分进程写失败。而写失败后如果有重试,将会耗费大量资源。因此,乐观锁通常用于读多写少的场景。
悲观锁
取数据时总是假定其他人会修改,因此取数据前会上锁。如果有多个进程并发修改数据,最终只能有一个进程成功上锁并修改数据。
锁的互斥属性
共享锁(读锁、S 锁)
不同的人能共享同一份资源。
如多个事务可以同时查看某行数据,对该行数据上共享锁,防止数据被改。
在 mysql 中通常使用语句 select * from user where id = 1 LOCK IN SHARE MODE;
来设置共享锁。
排它锁(写锁、X 锁)
不同的人不能共享同一份资源。
如多个事务可以同时修改某行数据,要对修改的数据上排它锁,多个排它锁之间会相互排斥,不能兼容。
在 mysql 中通常使用语句 select * from user where id = 1 FOR UPDATE;
来设置排他锁。
锁的兼容性
对于同一行数据,有的类型的锁可以并存,有的则不行,具体如下:
共享锁 | 排它锁 | |
---|---|---|
共享锁 | √ | × |
排它锁 | × | × |
锁的粒度
全局锁
mysql 中进行数据备份时,可使用全局锁锁定整个库,Flush tables with read lock
,防止行数据、表被修改。
表锁
表数据锁
lock tables … read/write;
将表中数据锁住,使得不能修改表中的数据。
元数据锁(MDL)
表的元数据(Meta Data),是指用于描述表的结构、属性等信息。
当对表进行结构修改时,如字段的增删改、表属性的变更,会加 MDL 写锁。
当对表中数据增删改查时,会对表加 MDL 读锁,以防表中列结构的变动。
MDL 锁的互斥性如下:
读锁 | 写锁 | |
---|---|---|
读锁 | √ | × |
写锁 | × | × |
行锁
在 InnoDB 中,数据是以聚簇索引组织的,因此 InnoDB 的行锁加在聚簇索引的。而对于非聚簇索引,锁均会加在二级索引、主键索引上。
记录锁(Record Lock)
|
|
该行语句,对 id 为 1、3、5 的数据行上了排它记录锁,该锁是的粒度是某几行数据。
间隙锁(Gap Lock)
|
|
该语句,对 id 小于 10 的数据上锁,解锁前无法插入、修改 id 小于 10 的数据。
临键锁(Next Key Lock)
临键锁 = 记录锁 + 间隙锁,例如:
|
|
参考资料
极客时间,丁奇《MySQL 45 讲》
Author Jakseer
LastMod 2021-07-04