锁机制概述
MySQL锁机制保证多事务并发访问数据的一致性,防止脏读、丢失更新等问题。
锁的分类
按锁粒度分类
| 类型 | 范围 | 说明 |
|---|---|---|
| 全局锁 | 整个数据库 | 全库只读,备份场景 |
| 表级锁 | 整张表 | MyISAM默认,InnoDB支持 |
| 行级锁 | 单行数据 | InnoDB默认,高并发友好 |
| 页级锁 | 数据页 | BDB引擎使用 |
按锁类型分类
| 类型 | 符号 | 说明 |
|---|---|---|
| 共享锁 | S | 读锁,允许并发读 |
| 排他锁 | X | 写锁,独占访问 |
| 意向共享锁 | IS | 表级,表示有意获取行S锁 |
| 意向排他锁 | IX | 表级,表示有意获取行X锁 |
按锁模式分类
| 类型 | 说明 |
|---|---|
| Record Lock | 记录锁,锁单行 |
| Gap Lock | 间隙锁,锁区间(不含记录) |
| Next-Key Lock | 记录+间隙锁 |
InnoDB锁类型
共享锁(S Lock)
SQL
-- 读锁,允许并发读,阻塞写
SELECT * FROM orders WHERE id = 1 LOCK IN SHARE MODE;
-- 或 MySQL 8.0+
SELECT * FROM orders WHERE id = 1 FOR SHARE;
-- 其他事务可读,不可写
-- 事务1:持有S锁
-- 事务2:可获取S锁(并发读)
-- 事务2:无法获取X锁(阻塞)
排他锁(X Lock)
SQL
-- 写锁,独占访问,阻塞其他读写
SELECT * FROM orders WHERE id = 1 FOR UPDATE;
-- DML自动获取X锁
UPDATE orders SET amount = 100 WHERE id = 1;
DELETE FROM orders WHERE id = 1;
INSERT INTO orders VALUES (...);
-- 其他事务无法获取任何锁
-- 事务1:持有X锁
-- 事务2:无法获取S锁/X锁(阻塞)
意向锁
SQL
意向锁是表级锁,表示事务有意在行上加锁:
IS(意向共享锁):事务将在某些行上加S锁
IX(意向排他锁):事务将在某些行上加X锁
作用:快速判断表是否有行锁冲突
无需逐行检查是否有锁
锁兼容性矩阵
| 当前锁 | S | X | IS | IX |
|---|---|---|---|---|
| S | ✅ | ❌ | ✅ | ❌ |
| X | ❌ | ❌ | ❌ | ❌ |
| IS | ✅ | ❌ | ✅ | ✅ |
| IX | ❌ | ❌ | ✅ | ✅ |
SQL
说明:
✅ 兼容:可同时持有
❌ 冲突:需等待对方释放
表级锁
LOCK TABLES
SQL
-- 读锁(共享锁)
LOCK TABLE orders READ;
-- 可读,不可写,其他事务可读
UNLOCK TABLES;
-- 写锁(排他锁)
LOCK TABLE orders WRITE;
-- 可读写,其他事务阻塞
UNLOCK TABLES;
元数据锁(MDL)
SQL
-- DDL操作自动获取MDL锁
ALTER TABLE orders ADD COLUMN new_col INT;
-- MDL锁类型:
-- MDL_SHARED:读操作
-- MDL_EXCLUSIVE:DDL操作
-- DDL期间阻塞所有DML
-- 长事务会阻塞DDL
全局锁
使用场景
SQL
-- 全库只读,用于备份
FLUSH TABLES WITH READ LOCK;
-- 执行备份
-- mysqldump --single-transaction(推荐,不锁表)
-- 释放全局锁
UNLOCK TABLES;
行级锁实现
Record Lock
SQL
-- 锁定单行记录
UPDATE orders SET amount = 100 WHERE id = 1;
-- 对id=1的记录加X锁
-- 索引匹配才生效,否则退化为表锁
UPDATE orders SET amount = 100 WHERE user_id = 1;
-- 若user_id有索引:行锁
-- 若user_id无索引:表锁(扫描所有行)
Gap Lock
SQL
-- 锁定记录之间的间隙
-- 防止幻读(其他事务插入)
-- 示例:id有值1,5,10
SELECT * FROM orders WHERE id > 5 AND id < 10 FOR UPDATE;
-- 锁定间隙(5,10),防止插入id=6,7,8,9
Next-Key Lock
SQL
-- Record Lock + Gap Lock
-- 锁定记录及其前间隙
-- 示例:id有值1,5,10
SELECT * FROM orders WHERE id = 5 FOR UPDATE;
-- 锁定(1,5]区间
-- 防止插入id=2,3,4和修改id=5
锁的获取时机
| 操作 | 锁类型 |
|---|---|
| SELECT(普通) | 无锁(MVCC) |
| SELECT ... LOCK IN SHARE MODE | S锁 |
| SELECT ... FOR UPDATE | X锁 |
| INSERT | X锁 |
| UPDATE | X锁 |
| DELETE | X锁 |
text
普通SELECT使用MVCC快照读,不加锁
锁定读和DML操作会加锁
查看锁信息
查看当前锁
text
-- MySQL 8.0+
SELECT * FROM performance_schema.data_locks;
-- 锁等待关系
SELECT * FROM performance_schema.data_lock_waits;
-- MySQL 5.7
SELECT * FROM information_schema.INNODB_LOCKS;
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
-- 当前事务
SELECT * FROM information_schema.INNODB_TRX;
查看锁等待
text
SELECT
r.trx_id AS waiting_trx,
r.trx_mysql_thread_id AS waiting_thread,
b.trx_id AS blocking_trx,
b.trx_mysql_thread_id AS blocking_thread,
r.trx_query AS waiting_query
FROM information_schema.INNODB_LOCK_WAITS w
JOIN information_schema.INNODB_TRX r ON w.requesting_trx_id = r.trx_id
JOIN information_schema.INNODB_TRX b ON w.blocking_trx_id = b.trx_id;
要点总结
- MySQL锁分为全局锁、表锁、行锁三种粒度
- InnoDB默认行级锁,支持高并发
- 共享锁(S)允许并发读,排他锁(X)独占访问
- 意向锁(IS/IX)是表级锁,快速判断行锁冲突
- 行锁包括Record Lock、Gap Lock、Next-Key Lock
- 普通SELECT不加锁(MVCC),DML和锁定读加锁
- 通过performance_schema查看锁信息
📝 发现内容有误?点击此处直接编辑