MySQL的锁机制是保障数据一致性和事务隔离性的核心,其设计较为复杂,涉及不同存储引擎与业务场景。为了帮助开发者建立系统的认知,我们通常可以从以下四个维度来系统性地理解MySQL的锁。
一、按锁的“粒度”分类(最常见)
1. 表级锁(Table Lock)
此锁会锁定整张表,其特点是锁粒度最大、加锁开销最小,但并发度最低,容易发生锁冲突。
- 适用场景:主要见于MyISAM引擎,或在执行DDL(如
ALTER TABLE)操作时。
- 主要特点:
- 加锁与释放锁的速度很快。
- 并发能力弱,写操作会阻塞其他所有的读写操作,读操作会阻塞其他写操作。
2. 行级锁(Row Lock)✔ InnoDB使用最广泛
行锁仅锁定需要访问的数据行,粒度小,能极大提升数据库的并发处理能力。
- 主要类型:
- 行共享锁(S Lock)
- 行排他锁(X Lock)
- 主要特点:
- 并发性能优异。
- 加锁、释放锁的开销较大。
- 在高并发场景下,可能产生死锁问题。
3. 页级锁(Page Lock)
锁的粒度介于表锁和行锁之间,会锁定一页数据(通常为16KB)。
二、按锁的“读写”性质分类
1. 共享锁(Shared Lock,S 锁)
又称为“读锁”。一个事务获取某行的共享锁后,自身可以读该行,其他事务也可以读该行,但任何事务都不能写该行。
2. 排他锁(Exclusive Lock,X 锁)
又称为“写锁”。一个事务获取某行的排他锁后,自身可以读写该行,其他事务既不能读也不能写该行。
三、按“意向”分类(InnoDB 特有)
意向锁是一种表级锁,用于表明某个事务“有意向”在表中的某些行上加特定类型的锁,从而避免在加表锁时需要逐行检查是否有冲突的行锁。
1. 意向共享锁(IS)
表示事务计划对表中的某些行加共享锁(S锁)。
2. 意向排他锁(IX)
表示事务计划对表中的某些行加排他锁(X锁)。
工作机制:当你要给某一行加X锁时,必须先成功给其所在的表加上IX锁。这种机制极大地提升了InnoDB在表级操作时的锁冲突检测效率。
四、InnoDB 特有的行级锁(核心考点)
1. 记录锁(Record Lock)
锁定索引中的一条具体记录。
- 示例:
SELECT * FROM user WHERE id = 10 FOR UPDATE; 会锁住id=10这条索引记录。
2. 间隙锁(Gap Lock)
锁定索引记录之间的“间隙”(一个开区间),防止其他事务在间隙中插入新数据,从而解决“幻读”问题。
- 示例:锁住
id在(10, 20)之间的这个范围,即使id=15的记录不存在,也无法被插入。
3. 临键锁(Next-Key Lock)✔ 默认模式
InnoDB在可重复读(RR)隔离级别下的默认行锁算法。它是记录锁(Record Lock)与间隙锁(Gap Lock)的结合,锁定一个左开右闭的区间。
- 示例:锁定区间(10, 20],既锁定了
id=20的记录,也锁定了(10, 20)这个间隙。
4. 插入意向锁(Insert Intention Lock)
一种特殊的间隙锁。当多个事务试图在同一个间隙中插入不同位置的数据时,它们会互相兼容地加上插入意向锁,不会彼此阻塞,以此提升插入并发效率。
5. 自增锁(AUTO-INC Lock)
一种特殊的表级锁,用于在表存在AUTO_INCREMENT列时,保障自增主键值的唯一性和连续性。
- 模式:通过
innodb_autoinc_lock_mode参数可配置为传统表锁模式或更轻量的交错模式。
五、按“是否阻塞”分类
1. 乐观锁(Optimistic Lock)
并非数据库内置的锁,而是一种并发控制思想。它假设多事务并发冲突的概率较低,因此在更新数据时才进行冲突检测(通常基于版本号或时间戳)。
2. 悲观锁(Pessimistic Lock)
即数据库提供的排他锁(X锁)。它假设并发冲突总会发生,因此在操作数据前就先加锁,确保独占。
- 适用场景:写操作频繁,冲突概率高的业务。
- 典型实现:使用
SELECT ... FOR UPDATE。
六、按“DDL/DML”分类
1. 元数据锁(MDL Lock)
MySQL 5.5+引入,用于保护表结构(元数据)的一致性,避免在查询或修改表数据时,表结构被更改。
- 读锁(共享):在执行DML(
SELECT, INSERT, UPDATE, DELETE)时自动加MDL读锁。
- 写锁(排他):在执行DDL(如
ALTER TABLE)时自动加MDL写锁。
- 常见问题:一个未提交的长事务(持有MDL读锁)会阻塞所有DDL操作;反过来,一个DDL操作(持有MDL写锁)会阻塞后续所有DML操作。这是运维中需要警惕的阻塞场景。
2. 备份锁(Backup Lock)
MySQL 8.0引入,用于在在线物理备份期间锁定,以阻止可能影响备份一致性的DDL操作,同时最小化对普通DML操作的影响。
七、加锁总结表
| 锁类型 |
发生位置 |
核心特点 |
典型场景/示例 |
| 表锁 |
表 |
粒度大,加锁快,并发低 |
MyISAM引擎,DDL操作 |
| 行锁 |
索引记录 |
粒度小,并发高,开销大 |
InnoDB引擎的DML操作 |
| 共享锁(S) |
行 |
读锁,允许多个事务并发读 |
SELECT ... LOCK IN SHARE MODE |
| 排他锁(X) |
行 |
写锁,独占访问 |
SELECT ... FOR UPDATE |
| 意向锁(IS/IX) |
表 |
辅助锁,提升锁冲突检测效率 |
InnoDB自动管理 |
| 记录锁 |
行 |
精确锁定单条索引记录 |
主键/唯一索引等值查询 |
| 间隙锁 |
索引间隙 |
防止幻读,锁定范围 |
范围查询,非唯一索引等值查询 |
| 临键锁 |
行+间隙 |
默认锁类型,解决幻读 |
RR隔离级别下的索引查询 |
| 自增锁 |
表 |
保护自增列唯一性 |
插入带AUTO_INCREMENT列的表 |
| MDL锁 |
表结构 |
控制DDL与DML的并发 |
执行ALTER TABLE时 |
总结
MySQL的锁体系以表级锁、行级锁和页锁为基本粒度。现代InnoDB引擎的核心是行级锁,其下又衍生出共享锁、排他锁、意向锁、记录锁、间隙锁、临键锁、插入意向锁和自增锁等丰富类型。此外,元数据锁(MDL)是保护表结构的关键。不同的锁在性能与并发安全之间进行权衡,开发者需根据实际业务场景和隔离级别,深入理解其原理,才能编写出高效、安全的数据库应用。
|