MySQL 的锁机制是实现并发控制的核心,不同层级的锁适用于不同场景,以下是对其锁类型的系统分类及详细说明:
一、按锁粒度划分
1. 全局锁(Global Lock)
-
用途:锁定整个数据库实例,用于全库备份。
-
命令:
FLUSH TABLES WITH READ LOCK; -- 加全局读锁 UNLOCK TABLES; -- 释放锁
-
影响:阻塞所有写操作及DDL操作,仅允许读操作。
2. 表级锁(Table-Level Lock)
-
表锁(Table Lock):
-
MyISAM引擎使用,分为:
- 表共享读锁(S锁):允许其他会话读,阻塞写。
- 表独占写锁(X锁):阻塞其他会话的读写。
-
命令:
LOCK TABLES table_name READ; -- 加读锁 LOCK TABLES table_name WRITE; -- 加写锁 UNLOCK TABLES; -- 释放锁
-
-
元数据锁(Metadata Lock, MDL):
- 自动加锁:访问表时自动加MDL读锁,修改结构时加MDL写锁。
- 问题:长事务可能导致DDL阻塞(如ALTER TABLE等待)。
-
意向锁(Intention Locks):
- 作用:快速判断表内是否有行级锁冲突,减少锁检查开销。
- 类型:
- 意向共享锁(IS):表明事务意图对某些行加S锁。
- 意向排他锁(IX):表明事务意图对某些行加X锁。
3. 行级锁(Row-Level Lock)
- InnoDB引擎支持,锁定索引记录,类型包括:
- 记录锁(Record Lock):锁定索引中的某一行。
- 间隙锁(Gap Lock):锁定索引记录之间的间隙,防止幻读。
- 临键锁(Next-Key Lock):记录锁 + 间隙锁,锁定左开右闭区间。
- 插入意向锁(Insert Intention Lock):插入前对间隙加锁,允许不同插入位置的并发。
- 自增锁(AUTO-INC Lock):
- 用途:确保自增列(AUTO_INCREMENT)值的唯一性。
- 优化:MySQL 8.0引入轻量级锁(互斥量),减少性能影响。
二、按锁模式划分
1. 共享锁(Shared Lock, S锁)
-
行为:允许其他事务加S锁,阻塞X锁。
-
使用场景:
SELECT ... LOCK IN SHARE MODE; -- 显式加S锁
2. 排他锁(Exclusive Lock, X锁)
-
行为:阻塞其他事务的S锁和X锁。
-
使用场景:
SELECT ... FOR UPDATE; -- 显式加X锁
三、按锁策略划分
1. 悲观锁(Pessimistic Locking)
- 假设:认为并发冲突频繁,提前加锁。
- 实现:通过
SELECT ... FOR UPDATE
显式加锁。
2. 乐观锁(Optimistic Locking)
-
假设:认为冲突较少,通过版本号或时间戳控制。
-
实现:
UPDATE table SET column = new_value, version = version + 1 WHERE id = 1 AND version = old_version;
四、锁的兼容性与冲突
已存在的锁 | IS锁(新请求) | IX锁(新请求) | S锁(新请求) | X锁(新请求) |
---|---|---|---|---|
IS锁 | ✅ | ✅ | ✅ | ❌ |
IX锁 | ✅ | ✅ | ❌ | ❌ |
S锁 | ✅ | ❌ | ✅ | ❌ |
X锁 | ❌ | ❌ | ❌ | ❌ |
五、不同隔离级别的锁策略
隔离级别 | 锁机制 |
---|---|
READ UNCOMMITTED | 不加锁(通过快照读),可能脏读。 |
READ COMMITTED | 行级锁(记录锁),无间隙锁,允许幻读。 |
REPEATABLE READ | 临键锁(Next-Key Lock)防止幻读,默认隔离级别。 |
SERIALIZABLE | 所有读操作隐式加共享锁,完全串行化。 |
六、锁的监控与诊断
1. 查看锁信息
SHOW ENGINE INNODB STATUS; -- 查看Inno引擎状态(含锁信息)
SELECT * FROM information_schema.INNODB_LOCKS; -- 当前持有的锁
SELECT * FROM information_schema.INNODB_LOCK_WAITS; -- 锁等待关系
2. 常见问题
- 死锁:事务相互等待锁释放,InnoDB自动检测并回滚代价较小的事务。
- 锁等待超时:由参数
innodb_lock_wait_timeout
控制(默认50秒)。
七、示例场景
场景1:防止超卖(临键锁)
-- 事务1:扣减库存
BEGIN;
SELECT stock FROM products WHERE id = 1 FOR UPDATE; -- 加X锁
UPDATE products SET stock = stock - 1 WHERE id = 1;
COMMIT;
- 作用:临键锁防止其他事务插入新记录,确保库存准确。
场景2:批量插入(间隙锁)
-- 事务1:查询范围数据
BEGIN;
SELECT * FROM orders WHERE amount > 100 FOR UPDATE; -- 对间隙加锁
- 作用:阻止其他事务在
amount > 100
范围内插入新数据。
总结
MySQL通过多粒度锁(全局锁、表锁、行锁)和多种锁模式(S/X锁、意向锁)实现高效的并发控制。合理选择事务隔离级别和锁策略(如临键锁防幻读、乐观锁降级冲突)是优化性能的关键。监控工具和诊断命令可帮助快速定位锁争用问题。