返回归档
🔍MySQL

MySQL-锁

文章目录

锁的分类

一、按照锁的粒度分类

1. 全局锁(Global Lock)

对整个数据库实例进行加锁,使其处于只读状态。

使用场景

  • 全库逻辑备份
  • 全库一致性快照

使用方式

-- 加全局锁
FLUSH TABLES WITH READ LOCK;

-- 解锁
UNLOCK TABLES;

2. 表级锁(Table Lock)

2.1 表锁(Table Lock)

对整张表进行加锁,阻塞其他用户对该表的所有读写操作。

使用场景

  • 表维护操作
  • 全表数据更改

语法

-- 加锁
LOCK TABLES table_name READ/WRITE;

-- 解锁
UNLOCK TABLES;

2.2 元数据锁(MDL Lock)

自动加锁,保护表结构。

触发场景

  • 查询操作自动加 MDL 读锁
  • DDL 操作自动加 MDL 写锁

示例

-- 查询时自动加 MDL 读锁
SELECT * FROM table_name;

-- DDL 操作自动加 MDL 写锁
ALTER TABLE table_name ADD COLUMN column_name INT;

2.3 意向锁(Intention Lock)

表级锁,为了支持多粒度锁定。

类型

  • 意向共享锁(IS)
  • 意向排他锁(IX)

2.4 自增锁(AUTO-INC Lock)

用于保证自增字段的唯一性。

应用

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50)
);

3. 行级锁(Row Lock)

3.1 记录锁(Record Lock)

锁定单个行记录。

示例

-- 排他锁
SELECT * FROM users WHERE id = 1 FOR UPDATE;

-- 共享锁
SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;

3.2 间隙锁(Gap Lock)

锁定索引记录之间的间隙,防止幻读。

示例

-- 锁定 id 在 1-10 之间的间隙
SELECT * FROM users WHERE id > 1 AND id < 10 FOR UPDATE;

3.3 临键锁(Next-Key Lock)

记录锁和间隙锁的组合。

二、按照使用机制分类

1. 读锁(共享锁,S锁)

允许多个事务同时读取数据。

特点

  • 可以并发读
  • 阻塞写操作

2. 写锁(排他锁,X锁)

单独占有数据,阻塞其他读写操作。

特点

  • 独占访问
  • 阻塞其他读写

三、按照加锁机制分类

1. 乐观锁

假设数据一般情况下不会发生冲突。

实现方式

-- 使用版本号
UPDATE users
SET data = 'new_value',
    version = version + 1
WHERE id = 1 AND version = 1;

-- 使用时间戳
UPDATE users
SET data = 'new_value',
    update_time = NOW()
WHERE id = 1 AND update_time = '2024-01-01 00:00:00';

2. 悲观锁

假设数据一定会发生冲突。

实现方式

-- 使用 FOR UPDATE 子句
BEGIN;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
UPDATE users SET data = 'new_value' WHERE id = 1;
COMMIT;

死锁是什么

死锁是两个或多个事物相互持有对方需要的锁,导致这些事物都无法继续执行,形成一个循环等待的状态

场景图解:

事务1: 拥有A ----等待----> B
   ^                      |
   |                      |
   |                      v
事务2: 拥有B ----等待----> A

形成了一个等待环路:事务1 -> 事务2 -> 事务1