锁的分类
一、按照锁的粒度分类
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