更新时间:2023-08-28
MySQL 中按锁访问级别可以分为共享锁和排他锁,根据锁粒度可以分为用户级别的锁、刷新锁、元数据锁、显示表锁、隐式表锁、记录锁、GAP 锁、Next-key 锁、插入意向锁、自增锁、备份锁、日志锁。这其中备份锁及日志锁为 MySQL 8.0 新引入的特性,而用户级别的锁不会经常使用。
刷新锁
刷新锁是表级锁,ANALYZE TABLE、FLUSH TABLE 等都是刷新锁,最常见的刷新锁就是备份中会用到的 FLUSH TABLE WITH READ LOCK 命令。此命令会获取实例中所有的表的共享读锁,此时其他事务的排它锁会被阻塞。
元数据锁
元数据锁是在 MySQL 5.5 中引入的,目的是为了保护方案(schema),从而确保当前查询或视为依赖于方案时,该方案信息保持不变。元数据锁在表级别上工作,但应该将其视为表级锁的独立类型,因为它不会保护表中的数据。
显示表锁
lock table 和 flush table with read lock 语句获得显示表锁。由于显示锁被视为元数据锁,因此在 metadata_locks 中表现与隐式元数据锁相同。
隐式表锁
隐式表锁也称之为意向锁,按官方的定义意向锁即是表锁,这是因为 MySQL 的上锁机制是从上到下的,比如获取行锁,会先在表上获取一个意向锁,之后在获取行锁。常见的语句有 select … [for update | for share] 以及 DML 语句等会获取行级锁,也会先在其对应的表中获取意向锁。
InnoDB 中锁之间的兼容性列表
|
排它锁(X) |
意向排它锁(IX) |
共享锁(S) |
意向共享锁(IS) |
排它锁(X) |
× |
× |
× |
× |
意向排它锁(IX) |
× |
√ |
× |
√ |
共享锁(S) |
× |
× |
√ |
√ |
意向共享锁(IS) |
× |
√ |
√ |
√ |
记录锁
记录锁通常称为行锁。
gap 锁、Next-key 锁
gap 锁用于保护两条记录之间的空间。它可以在簇聚索引的行中,也可以在二级索引中。Next-key 锁是记录锁 + GAP 锁的组合。
插入意向锁
对于表级锁,InnoDB 具有意向锁,从而用于确定事务以共享方式,还是独占方式来使用。同样,InnoDB 在记录级别也具有插入意向锁。因此,该锁位于尚未创建的记录上(它就是一个 gap 锁),而不是现有记录上。
自增锁
将数据插入带有自动递增计数器的表中时,就有必要对计数器进行保护,以确保两个事务都能获得唯一值。
InnoDB 支持三种自增锁模式,使用 innodb_autoinc_lock_mode 选项来设置锁模式
使用 innodb_autoinc_lock_mode 选项来设置锁模式
值 |
模式 |
描述 |
0 |
传统 |
MySQL 5.0 及更早版本中的锁行为。锁将会保持到语句结束。 |
1 |
连续 |
对于那些在开始就知道行数的 INSERT 语句,将在轻量级互斥量下分配所需要的自动增量数值,从而避免自增锁。对于行数未知的语句,则采用自增锁并将其保持在语句末尾。MySQL 5.7 及更早版本中的设置 |
2 |
交错 |
永远都不适用自增锁,并且可能插入并发插入的自增值。仅当禁用了二进制日志,或将 binlog_format 设置为 ROW 时,该模式才安全。它是 MySQL 8.0 中的默认值 |
RDS MySQL 使用 2 作为默认值。
执行过程中,由以上锁中的一种或多种锁的使用会产生锁阻塞,甚至死锁。