在本篇开始阅读前,建议看下《mysql数据库 意向锁(初篇)》章节,对意向所有个大概了解。
一、用“分层锁”的图示理解意向锁(核心)
innodb 使用的是 多粒度锁(multi-granularity locking):
数据库
└── 表(意向锁 is / ix)
└── 行(s / x)规则一句话版
想锁行,必须先在表上“打个招呼”
示例:更新一行数据
start transaction; update orders set status = 'paid' where id = 10;
锁的实际过程是:
1️⃣ 给 orders 表加 ix(意向排他锁) 2️⃣ 给 id = 10 这一行加 x(排他锁)
👉 意向锁 = “我打算动你表里的某些行”
二、为什么没有意向锁会很惨?
假设:没有意向锁
- 表
orders有 1000 万行 - 事务 a:更新其中 1 行
- 事务 b:想加表锁
lock table orders write;
😱 mysql 只能:
- 扫描 1000 万行
- 看看有没有行锁
为此,就会引发:👉 性能灾难
有了意向锁之后
| 操作 | 检查内容 |
|---|---|
| 行锁 | 不管表锁 |
| 表锁 | 只看 is / ix |
🚀 o(1) 判断是否冲突
三、意向锁 vs 表锁 vs 行锁(对比表)
| 锁类型 | 级别 | 是否阻塞行锁 | 是否阻塞表锁 |
|---|---|---|---|
| is | 表 | ❌ | 阻塞表 x |
| ix | 表 | ❌ | 阻塞表 s / x |
| s | 行 | 行级互斥 | — |
| x | 行 | 行级互斥 | — |
| s(表) | 表 | 阻塞 ix | 阻塞 x |
| x(表) | 表 | 全阻塞 | 全阻塞 |
📌 重点:
意向锁几乎只和“表锁”打架,不和“行锁”打架
四、为什么 myisam 不需要意向锁?
myisam 的锁模型
- ❌ 不支持行锁
- ✅ 只有表锁
要么整张表读 要么整张表写
👉 不存在:
- 行锁
- 表锁与行锁并存
- 自然 不需要意向锁
innodb 的优势(但更复杂)
| 存储引擎 | 并发 | 锁模型 |
|---|---|---|
| myisam | 低 | 表锁 |
| innodb | 高 | 行锁 + 意向锁 |
五、一个非常经典的死锁场景(面试常考)
场景描述
表 user:
| id | name |
|---|---|
| 1 | a |
| 2 | b |
事务 a
start transaction; select * from user where id = 1 for update;
锁状态:
user 表:ix id=1 行:x
事务 b
start transaction; lock table user write;
b 想要:
user 表:x
❌ 但被 a 的 ix 阻塞
接着事务 a 再做:
select * from user where id = 2 for update;
此时:
- a 等待表锁释放
- b 等待 ix 消失
💥 死锁形成
👉 innodb 会:
- 自动检测
- 回滚其中一个事务
六、如何在生产中“看到”意向锁?
1️⃣ 查看当前锁(mysql 8.0)
select * from performance_schema.data_locks;
你会看到类似:
object_name = orders lock_type = table lock_mode = ix
2️⃣ 常见 lock_mode 含义
| lock_mode | 含义 |
|---|---|
| is | 意向共享 |
| ix | 意向排他 |
| s | 共享 |
| x | 排他 |
七、一句话总结
意向锁是 innodb 自动维护的表级锁,用来声明事务将对表中的某些行加行锁,从而在加表锁时避免扫描所有行锁,是多粒度锁机制的关键。
到此这篇关于一文搞懂mysql 数据库意向锁的文章就介绍到这了,更多相关mysql 数据库意向锁内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论