Files
blog/src/content/posts/中间件/MySQL/MySQL中的全局锁表级锁行级锁机制.md
meowrain 7b7e32ddd4
Some checks failed
Clean ESA Versions on Main / clean-esa-versions (push) Has been cancelled
init
2026-01-02 00:03:49 +08:00

201 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: MySQL全局锁表级锁行级锁
published: 2025-08-09
description: 'MySQL中的全局锁表级锁行级锁机制'
image: ''
tags: [全局锁,表级锁,行级锁]
category: '中间件 > MySQL'
draft: false
lang: ''
---
![](https://blog.meowrain.cn/api/i/2025/08/09/qrldag-1.webp)
# MySQL的锁
## 全局锁
如果要使用全局锁
要执行下面的命令:
```sql
flush table with read lock
```
![](https://blog.meowrain.cn/api/i/2025/08/09/quecvs-1.webp)
执行全局锁以后,数据库就变成只读状态了,插入和更新操作都会被阻塞
这个全局锁一般是用于数据库全局备份的。在备份数据库期间,不会因为数据和表结构的更新,出现备份文件的数据和预期的不一样。
![](https://blog.meowrain.cn/api/i/2025/08/09/qwcl26-1.webp)
可以看到会卡主
![](https://blog.meowrain.cn/api/i/2025/08/09/qwsqeo-1.webp)
解锁以后就可以插入了
备份数据库的时候又不想停机,可以在用 mysqldump的时候加上 --single-transaction参数就会在备份数据之前先开启事务。这种方法只适用于支持可重复读隔离级别的事务的存储引擎。
## 表级锁
MySQL中的表级锁有哪些
- 表锁
- 元数据锁
- 意向锁
- AUTO-INC锁
### 表锁
如果我们相对student表加上表锁
```sql
-- 允许当前会话读取被锁定的表,但是会组织其他会话对这些表进行写操作
lock table student_t read;
-- 表级别的独占锁,也就是写锁
-- 允许当前会话对表进行读写操作,但会阻止其他会话对这些表进行任何操作
lock table student_t write;
```
需要注意的是,表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。
### 元数据锁
元数据锁不需要显示调用因为当我们对数据库表进行操作的时候会自动给这个表加上MDL
当我们对一张表进行CRUD操作的时候加的是MDL读锁
当我们对一张表做结构变更操作的时候加的是MDL写锁
MDL是为了保证当用户对表执行CRUD操作的时候防止其他线程对这个表结构做变更。
比如说一个线程正在执行查询操作加了MDL读锁如果有其他线程来修改表结构就会被阻塞直到查询结束。
同理一个线程在修改表结构的时候申请了MDL写锁其他线程的查询操作就会被阻塞直到说表结构变更完成
### 意向锁
- 在使用InnoDB引擎的表里对某些记录加上共享锁之前需要先在表级别上加一个意向共享锁。
- 在使用InnoDB引擎的表里对某些记录加上独占锁之前需要先在表级别加上一个意向独占锁。
普通的select是不会加行级锁的因为它是用MVCC多版本并发控制实现的是无锁的。
不过select也是可以对记录加共享锁和独占锁的。
```sql
//
select ... lock in share mode;
//
select ... for update;
```
> 意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁和独占锁发生冲突。
意向锁的目的是为了快速判断表里是否有记录被加锁。
比如说,当一个事务想要对某个记录加锁时,可以先检查表级的意向锁,如果表级的意向锁是共享锁,就说明有其他事务正在读取这个表中的记录;如果是独占锁,就说明有其他事务正在修改这个表中的记录。
如果表级的意向锁是共享锁,那么其他事务可以对表上共享锁,但是不能加独占锁。如果是表级意向锁是独占锁,其他事务就不能对表上加任何锁。
### AUTO-INC锁
表里的主键通常会设置成自增的,这是通过主键字段声明 AUTO_INCREMENT 属性实现的。
之后可以在插入数据的时候,可以不指定主键的值,数据库会自动给主键赋值递增的值,这主要是通过 AUTO-INC锁实现的。
AUTO-INC锁是特殊的表锁机制锁不是在一个事务提交后才释放而是在执行完插入语句后就会立刻释放。
在插入数据的时候会加一个表级别的AUTO-INC锁然后为被 `AUTO_INCREMENT` 修饰的字段赋值递增的值等插入语句执行完成后才会把AUTO-INC锁释放掉。
那么在一个事务持有AUTO-INC锁的过程中其他事务如果要向该表插入语句都会被阻塞从而保证了插入数据的时候被AUTO_INCREMENT修饰的字段的值是连续递增的。
因此在MySQL5.1.22开始,InnoDB存储引擎提供了一种轻量级的锁来实现自增。
一样也是在插入数据的时候会为被auto_increment修饰的字段加上轻量级锁然后给该字段赋值一个自增的值然后就把这个轻量级锁释放了不需要等待整个插入语句执行完成后才释放锁。
## 行级锁
InnoDB引擎是支持行级锁的而MyISAM不支持行级锁
可以使用下面这两个方式,这种查询会加锁的语句称为锁定读。
```sql
//
select ... lock in share mode;
//
select ... for update;
```
![](https://blog.meowrain.cn/api/i/2025/08/09/10o8753-1.webp)
### 行级锁类型
有三类:
- Record Lock记录锁也就是仅仅把一条记录锁上
- Gap Lock 间隙锁,锁定一个范围,但是不包含记录本身
- Next-Key Lock Record Lock + Gap Lock的组合锁定一个范围并且锁定记录本身
### Record Lock 记录锁
Record Lock被称为记录锁锁住的锁一条记录而且记录锁是有S锁和X锁之分的。
- 当一个事务对一条记录加了S型记录锁后其他事务也可以继续对该记录加S型记录锁但是不可以对该记录加X型记录锁
- 当一个事务对一条记录加了X型记录锁后其他事务不可以对该记录加S型记录锁也不可对该记录加X型记录锁
![](https://blog.meowrain.cn/api/i/2025/08/09/10qlyoo-1.webp)
### Gap Lock 间隙锁
Gap Lock被称为间隙锁存在于可重复读隔离级别和串行化隔离级别目的是为了解决可重复读隔离级别下幻读的现象
假设表中有一个范围id为(3,5)的间隙锁那么其他事务就无法插入id = 4这条记录了这样就有效地防止了幻读现象的发生。
间隙锁虽然也存在X型和S型间隙锁但是没什么区别间隙锁之间是兼容的两个事务可以同时持有并包含共同间隙范围的间隙锁并不存在互斥关系因为间隙锁的目的是防止插入幻影记录而提出的。
![](https://blog.meowrain.cn/api/i/2025/08/09/124cfwm-1.webp)
![](https://blog.meowrain.cn/api/i/2025/08/09/124ikdt-1.webp)
![](https://blog.meowrain.cn/api/i/2025/08/09/12542r3-1.webp)
### Next-Key Lock 临键锁
Next-Key-Lock称为临键锁是Record Lock和Gap Lock的组合。锁定一个范围并且锁定记录本身。
假设表中有个范围id为(3,5]的next-key-lock那么其它事务既不能插入id = 4的记录也不能修改id = 5这条记录。
所以next-key lock既能保护该记录又能阻止其它事务将新记录插入到被保护记录前面的间隙中。
Next-key lock 是数据库中 InnoDB 存储引擎(常见于 MySQL使用的一种锁机制主要用于防止 **幻读Phantom Read** 问题确保事务在可重复读Repeatable Read隔离级别下的一致性。它的意义在于通过结合 **记录锁Record Lock****间隙锁Gap Lock**,对索引记录及其前后的间隙进行锁定,从而避免其他事务插入或修改数据导致的幻读现象。
#### 具体意义和作用:
1. **防止幻读**
- 幻读是指在同一事务中,多次执行相同查询时,由于其他事务插入了新记录,导致查询结果集发生变化。
- Next-key lock 锁定一个索引记录及其前后的间隙,防止其他事务插入新记录到这个范围内,从而保证查询结果的稳定性。
2. **结合记录锁和间隙锁**
- **记录锁**:锁定具体的索引记录,防止其他事务修改或删除该记录。
- **间隙锁**:锁定索引记录之间的“间隙”,防止其他事务在该间隙内插入新记录。
- Next-key lock 是两者的结合,锁定一个记录及其左侧或右侧的间隙。例如,对于索引值 10Next-key lock 可能锁定 (5, 10] 范围(假设 5 是前一个索引值)。
3. **提高并发控制的精度**
- Next-key lock 是一种范围锁,比表级锁更精细,能够在保证数据一致性的同时,尽量减少锁的粒度,提高并发性能。
4. **支持可重复读隔离级别**
- 在 MySQL 的可重复读Repeatable Read隔离级别下Next-key lock 是默认的锁机制,用于确保事务在多次读取时看到一致的数据快照。
#### 工作原理:
- 当事务对某一行记录进行操作(例如 SELECT ... FOR UPDATE 或 UPDATEInnoDB 会锁定该记录以及其前后的间隙。
- 例如,假设表中有一个索引列 `id` 包含值 10、20、30。如果事务 A 对 `id = 20` 加锁Next-key lock 可能会锁定 (10, 20] 或 (20, 30] 的范围,防止其他事务插入值在该范围内的记录。
#### 注意事项:
1. **性能影响**Next-key lock 锁定范围较大,可能导致锁冲突,降低并发性能。
2. **死锁风险**:多个事务竞争相同的间隙锁可能导致死锁,需要合理设计事务逻辑。
3. **依赖索引**Next-key lock 依赖于索引。如果查询没有使用索引,可能会退化为表级锁,影响性能。
总结来说Next-key lock 的核心意义在于通过锁定记录和间隙,防止幻读,维护事务隔离级别的一致性,同时在高并发场景下提供较好的数据保护机制。
### 插入意向锁
一个事务在插入一条记录的时候需要判断插入位置是否已被其他事务加了间隙锁next-key lock 也包含间隙锁)。
如果有的话,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。