锁分类
全局锁
锁定整个数据库,所有表只读。表级锁
表锁
| 锁类型 | 当前会话 | 其他会话 |
|---|---|---|
| 读锁 | 可读不可写 | 可读不可写 |
| 写锁 | 可读可写 | 不可读不可写 |
元数据锁(MDL)
访问表时自动加锁,无需手动操作。| 操作 | 锁类型 | 说明 |
|---|---|---|
| SELECT | MDL 读锁 | 可并发读 |
| DML | MDL 读锁 | 可并发读 |
| DDL | MDL 写锁 | 阻塞其他操作 |
意向锁
InnoDB 自动维护,用于表锁和行锁的协调。| 类型 | 说明 |
|---|---|
| IS | 意向共享锁 |
| IX | 意向排他锁 |
行级锁
InnoDB 支持行级锁,锁粒度最小,并发度最高。行锁类型
| 类型 | 说明 |
|---|---|
| Record Lock | 记录锁,锁单行 |
| Gap Lock | 间隙锁,锁索引间隙 |
| Next-Key Lock | 临键锁,Record + Gap |
共享锁与排他锁
| 锁类型 | S锁 | X锁 |
|---|---|---|
| S锁 | 兼容 | 冲突 |
| X锁 | 冲突 | 冲突 |
行锁加锁规则
默认锁类型:Next-Key Lock(左开右闭区间)| 场景 | 锁类型 |
|---|---|
| 唯一索引等值查询,记录存在 | Record Lock |
| 唯一索引等值查询,记录不存在 | Gap Lock |
| 唯一索引范围查询 | Next-Key Lock |
| 非唯一索引等值查询 | Next-Key Lock |
| 无索引 | 全表锁 |
间隙锁示例
假设 id 有值:1, 5, 10临键锁示例
死锁
两个事务互相等待对方释放锁。死锁示例
死锁处理
InnoDB 死锁检测:自动检测并回滚代价小的事务避免死锁
| 方法 | 说明 |
|---|---|
| 固定顺序访问 | 多表操作按固定顺序 |
| 大事务拆分 | 减少锁持有时间 |
| 使用低隔离级别 | RC 比 RR 锁更少 |
| 添加合理索引 | 避免全表锁 |
| 设置超时 | innodb_lock_wait_timeout |
锁优化
减少锁冲突
锁监控
锁常见问题
Q1: 为什么 UPDATE 不走索引会锁全表?
InnoDB 行锁是加在索引上的。没有索引,只能锁全表。Q2: INSERT 会加什么锁?
- 普通 INSERT:隐式锁(延迟加锁)
- INSERT … ON DUPLICATE KEY UPDATE:Next-Key Lock
- INSERT INTO … SELECT:共享 Next-Key Lock
Q3: 乐观锁和悲观锁?
| 类型 | 实现 | 适用场景 |
|---|---|---|
| 悲观锁 | SELECT … FOR UPDATE | 写多读少 |
| 乐观锁 | 版本号 / CAS | 读多写少 |