---
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 是两者的结合，锁定一个记录及其左侧或右侧的间隙。例如，对于索引值 10，Next-key lock 可能锁定 (5, 10] 范围（假设 5 是前一个索引值）。

3. **提高并发控制的精度**：
   - Next-key lock 是一种范围锁，比表级锁更精细，能够在保证数据一致性的同时，尽量减少锁的粒度，提高并发性能。

4. **支持可重复读隔离级别**：
   - 在 MySQL 的可重复读（Repeatable Read）隔离级别下，Next-key lock 是默认的锁机制，用于确保事务在多次读取时看到一致的数据快照。

#### 工作原理：
- 当事务对某一行记录进行操作（例如 SELECT ... FOR UPDATE 或 UPDATE），InnoDB 会锁定该记录以及其前后的间隙。
- 例如，假设表中有一个索引列 `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 也包含间隙锁）。

如果有的话，插入操作就会发生阻塞，直到拥有间隙锁的那个事务提交为止（释放间隙锁的时刻），在此期间会生成一个插入意向锁，表明有事务想在某个区间插入新记录，但是现在处于等待状态。