在数据库系统中,锁是保证数据一致性和并发控制的核心机制。MySQL作为流行的关系型数据库,提供了丰富多样的锁策略来应对不同的并发场景。理解MySQL锁的分类及其作用,对于优化数据库性能、避免死锁以及保证数据正确性至关重要。本文将从锁的粒度、锁的功能两个维度,系统梳理MySQL中的各类锁,并详细说明每种锁的用途、加锁方式及注意事项。
先贴张图方便理解

一、按锁的粒度分类
锁的粒度指的是锁定的范围大小,粒度越细,并发能力越强,但加锁开销也越大。MySQL中按粒度可分为:全局锁、表级锁和行级锁。
1. 全局锁
全局锁是对整个数据库实例加锁,加锁后整个数据库处于只读状态。通常用于全库逻辑备份,确保备份数据的一致性。
-
加锁语句:
FLUSH TABLES WITH READ LOCK;
-
作用:阻塞所有数据更新操作(INSERT、UPDATE、DELETE)和表结构变更(ALTER、DROP等),仅允许读取。
-
缺点:导致业务停滞,无法处理写请求。
-
优化方案:
-
对于使用InnoDB存储引擎的表,可利用事务的可重复读隔离级别,在备份时开启一个事务,利用MVCC(多版本并发控制)创建一致性快照,避免加全局锁。
-
使用mysqldump工具时,添加–single-transaction参数,该选项会在备份前启动一个事务,基于快照进行备份,从而避免全局锁。
-
2. 表级锁
表级锁锁定整张表,实现简单,开销较小,但并发度较低。MyISAM和InnoDB都支持表级锁。
2.1 表锁
通过LOCK TABLES语句显式加锁,可以加共享锁(读锁)或排他锁(写锁)。
-
表级共享锁:
LOCK TABLES user READ;
阻止其他会话对表进行写操作,当前会话只能读该表,不能访问其他表。
-
表级排他锁:
LOCK TABLES user WRITE;
阻止其他会话对该表进行任何读/写操作,当前会话可读写该表,但不能访问其他表。
2.2 元数据锁(MDL锁)
MDL锁是MySQL自动管理的表级锁,用于保护表结构定义。当对一个表执行SELECT(加MDL读锁)时,会阻止其他会话对该表执行DDL操作(如ALTER TABLE),直到当前事务提交。
-
释放时机:事务提交后自动释放。
-
作用:防止在查询过程中表结构被修改,保证元数据的一致性。
2.3 意向锁
意向锁是InnoDB自动维护的表级锁,用于快速判断表级锁与行级锁的兼容性,避免逐行检查。用户无法手动干预。
-
意向共享锁(IS锁):事务准备给表中的某些行加共享锁(S锁)时,先在表上加IS锁。
-
意向排他锁(IX锁):事务准备给表中的某些行加排他锁(X锁)时,先在表上加IX锁。
意向锁的兼容规则:
-
意向锁之间相互兼容(IS与IS、IS与IX、IX与IX均不冲突)。
-
意向锁与行级S锁/X锁也兼容,因为它们是在不同粒度上的锁。
-
但意向排他锁(IX)与表级共享锁(S)或表级排他锁(X)互斥,意向共享锁(IS)与表级共享锁(S)兼容,与表级排他锁(X)互斥。
| S锁(共享表锁) | 兼容 | 互斥 |
| X锁(独占表锁) | 互斥 | 互斥 |
2.4 自增锁(AUTO-INC锁)
自增锁是一种特殊的表级锁,用于保证自增列(AUTO_INCREMENT)值的唯一性和连续性。事务向包含自增列的表插入数据时,需要获取自增锁。
-
传统模式:语句执行期间持有自增锁,直到语句结束才释放,影响并发插入性能。
-
优化模式:MySQL 5.1.22起提供innodb_autoinc_lock_mode参数控制自增锁行为:
-
0(传统模式):采用AUTO-INC锁,语句执行完释放。
-
1(连续模式,MySQL 8.0前默认):普通INSERT申请到自增值后立即释放锁;批量插入(如INSERT … SELECT)需等待语句结束释放。
-
2(交错模式,MySQL 8.0后默认):使用轻量级互斥锁,多条插入语句可并发执行,性能最高。但需将binlog格式设置为ROW,以保证主从数据一致性。
-
3. 行级锁
行级锁仅锁定具体的数据行,并发度高,是InnoDB的核心特性。MyISAM不支持行级锁。
3.1 记录锁(Record Lock)
锁定单个行记录,是最基本的行锁。
-
加锁方式:
— 加共享记录锁(S锁)
SELECT … LOCK IN SHARE MODE;
— 或
SELECT … FOR SHARE; — MySQL 8.0+— 加排他记录锁(X锁)
SELECT … FOR UPDATE; -
特性:
-
对某行加S锁后,其他事务可加S锁,但不能加X锁。
-
对某行加X锁后,其他事务不能加任何锁(S或X)。
-
锁在事务提交或回滚后释放。
-
例如,对id=2的记录加X锁:
BEGIN;
SELECT * FROM user WHERE id = 2 FOR UPDATE;
— 其他事务无法修改id=2的记录
COMMIT;
3.2 间隙锁(Gap Lock)
间隙锁锁定一个范围(开区间),但不包括记录本身,目的是防止其他事务在该范围内插入新记录,从而避免幻读。
-
示例:表中已有id=1,2,3,5的记录,间隙锁锁定(1,5)范围,即禁止在id=2,3的位置插入新记录,但不影响id=5的记录。
-
作用范围:仅在可重复读(REPEATABLE READ)隔离级别下生效。
-
兼容性:不同事务可在同一间隙上加间隙锁,因为间隙锁只阻塞插入,不阻塞查询。
3.3 临键锁(Next-Key Lock)
临键锁是记录锁与间隙锁的组合,锁定一个范围,并包含记录本身。它是InnoDB在可重复读级别下解决幻读的主要手段。
-
示例:锁定(1,5]范围,即锁住id=2,3,5的记录,同时防止在(1,5)范围内插入新记录。
-
特性:不同事务对相同范围的X型临键锁是互斥的。
3.4 插入意向锁
插入意向锁是一种特殊的间隙锁,表示事务准备在某个间隙中插入新记录。它由InnoDB自动管理,用户无法干预。
-
作用:协调多个事务在同一个间隙内的插入操作,提高并发度。
-
兼容规则:
-
如果事务A持有某个间隙的间隙锁,事务B想要在同一间隙加插入意向锁,则B必须等待A释放间隙锁。
-
如果多个事务准备在同一个间隙的不同位置插入记录,它们的插入意向锁可以共存,互不阻塞。
-
插入意向锁与间隙锁互斥,但与记录锁不直接冲突(记录锁锁住的是记录本身)。
-
二、按锁的功能分类
无论是表级锁还是行级锁,从功能上都可以分为共享锁(S锁)和排他锁(X锁)。
-
共享锁(S锁):读锁,事务读取数据时获取。允许其他事务同时加S锁,但不允许加X锁。
-
排他锁(X锁):写锁,事务修改数据时获取。不允许其他事务再加任何锁(S或X)。
兼容性矩阵:
| S锁 | 兼容 | 互斥 |
| X锁 | 互斥 | 互斥 |
加锁语句示例:
— 加共享锁
SELECT … LOCK IN SHARE MODE; — MySQL 5.x
SELECT … FOR SHARE; — MySQL 8.x
— 加排他锁
SELECT … FOR UPDATE;
三、扩展:快照读与当前读
理解锁机制离不开对MySQL读取模式的认识。InnoDB支持两种读取方式:
1. 快照读
-
利用MVCC机制,读取的是记录的历史版本(快照),不加锁,因此不会阻塞其他事务。
-
仅在读已提交(RC)和可重复读(RR)隔离级别下生效。
-
RC级别下,每次执行SELECT都会获取最新的快照;RR级别下,仅在事务开始时获取一次快照,后续读取同一快照。
2. 当前读
-
读取记录的最新版本,并对读取的记录加锁(S锁或X锁),确保其他事务不能修改这些记录。
-
常见当前读操作:
SELECT … FOR UPDATE; — 加X锁
SELECT … LOCK IN SHARE MODE; — 加S锁
INSERT;
UPDATE;
DELETE;
四、总结
MySQL的锁机制复杂而精细,理解不同锁的作用和适用场景,有助于我们编写高效、可靠的并发事务。下表简要总结了主要锁类型及其用途:
| 全局锁 | 数据库 | 全库备份,保证一致性 |
| 表锁 | 表 | 显式锁定整张表,用于特定操作 |
| 元数据锁 | 表 | 保护表结构,防止DDL与DML冲突 |
| 意向锁 | 表 | 快速判断表锁与行锁的兼容性 |
| 自增锁 | 表 | 保证自增列的唯一性 |
| 记录锁 | 行 | 锁定单行记录 |
| 间隙锁 | 间隙 | 防止幻读,禁止在范围内插入 |
| 临键锁 | 行+间隙 | 记录锁与间隙锁的组合,解决幻读 |
| 插入意向锁 | 间隙 | 协调并发插入,提高插入性能 |
在实际开发中,合理选择隔离级别、优化SQL语句、避免长事务,都能减少锁冲突,提升系统并发能力。



