上海金融律师许锦忠 發表於 2026-1-10 11:20:27

一文搞懂MySQL 数据库意向锁

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、用&ldquo;分层锁&rdquo;的图示理解意向锁(核心)</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">规则一句话版</a></li><li><a href="#_lab2_0_1">示例:更新一行数据</a></li></ul><li><a href="#_label1">二、为什么没有意向锁会很惨?</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_2">假设:没有意向锁</a></li><li><a href="#_lab2_1_3">有了意向锁之后</a></li></ul><li><a href="#_label2">三、意向锁 vs 表锁 vs 行锁(对比表)</a></li><ul class="second_class_ul"></ul><li><a href="#_label3">四、为什么 MyISAM 不需要意向锁?</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_4">MyISAM 的锁模型</a></li><li><a href="#_lab2_3_5">InnoDB 的优势(但更复杂)</a></li></ul><li><a href="#_label4">五、一个非常经典的死锁场景(面试常考)</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_6">场景描述</a></li><li><a href="#_lab2_4_7">事务 A</a></li><li><a href="#_lab2_4_8">事务 B</a></li><li><a href="#_lab2_4_9">接着事务 A 再做:</a></li></ul><li><a href="#_label5">六、如何在生产中&ldquo;看到&rdquo;意向锁?</a></li><ul class="second_class_ul"><li><a href="#_lab2_5_10">1️⃣ 查看当前锁(MySQL 8.0)</a></li><li><a href="#_lab2_5_11">2️⃣ 常见 LOCK_MODE 含义</a></li></ul><li><a href="#_label6">七、一句话总结</a></li><ul class="second_class_ul"></ul></ul></div><p>在本篇开始阅读前,建议看下《<a href="https://www.jb51.net/database/356525swi.htm" target="_blank">MySQL数据库 意向锁(初篇)</a>》章节,对意向所有个大概了解。</p>
<p class="maodian"><a name="_label0"></a></p><h2>一、用&ldquo;分层锁&rdquo;的图示理解意向锁(核心)</h2>
<p>InnoDB 使用的是 <strong>多粒度锁(Multi-Granularity Locking)</strong>:</p>
<div class="jb51code"><pre class="brush:plain;">数据库
└── 表(意向锁 IS / IX)
      └── 行(S / X)</pre></div>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>规则一句话版</h3>
<blockquote><p><strong>想锁行,必须先在表上&ldquo;打个招呼&rdquo;</strong></p></blockquote>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>示例:更新一行数据</h3>
<div class="jb51code"><pre class="brush:sql;">START TRANSACTION;
UPDATE orders SET status = 'paid' WHERE id = 10;
</pre></div>
<p>锁的实际过程是:</p>
<div class="jb51code"><pre class="brush:sql;">1️⃣ 给 orders 表加 IX(意向排他锁)
2️⃣ 给 id = 10 这一行加 X(排他锁)</pre></div>
<p>👉 <strong>意向锁 = &ldquo;我打算动你表里的某些行&rdquo;</strong></p>
<p class="maodian"><a name="_label1"></a></p><h2>二、为什么没有意向锁会很惨?</h2>
<p class="maodian"><a name="_lab2_1_2"></a></p><h3>假设:没有意向锁</h3>
<ul><li>表 <code>orders</code> 有 <strong>1000 万行</strong></li><li>事务 A:更新其中 1 行</li><li>事务 B:想加表锁</li></ul>
<div class="jb51code"><pre class="brush:sql;">LOCK TABLE orders WRITE;
</pre></div>
<p>😱 MySQL 只能:</p>
<ul><li>扫描 1000 万行</li><li>看看有没有行锁</li></ul>
<p>为此,就会引发:👉 <strong>性能灾难</strong></p>
<p class="maodian"><a name="_lab2_1_3"></a></p><h3>有了意向锁之后</h3>
<table><thead><tr><th>操作</th><th>检查内容</th></tr></thead><tbody><tr><td>行锁</td><td>不管表锁</td></tr><tr><td>表锁</td><td>只看 IS / IX</td></tr></tbody></table>
<p>🚀 <strong>O(1) 判断是否冲突</strong></p>
<p class="maodian"><a name="_label2"></a></p><h2>三、意向锁 vs 表锁 vs 行锁(对比表)</h2>
<table><thead><tr><th>锁类型</th><th>级别</th><th>是否阻塞行锁</th><th>是否阻塞表锁</th></tr></thead><tbody><tr><td>IS</td><td>表</td><td>❌</td><td>阻塞表 X</td></tr><tr><td>IX</td><td>表</td><td>❌</td><td>阻塞表 S / X</td></tr><tr><td>S</td><td>行</td><td>行级互斥</td><td>&mdash;</td></tr><tr><td>X</td><td>行</td><td>行级互斥</td><td>&mdash;</td></tr><tr><td>S(表)</td><td>表</td><td>阻塞 IX</td><td>阻塞 X</td></tr><tr><td>X(表)</td><td>表</td><td>全阻塞</td><td>全阻塞</td></tr></tbody></table>
<p>📌 <strong>重点</strong>:</p>
<blockquote><p><strong>意向锁几乎只和&ldquo;表锁&rdquo;打架,不和&ldquo;行锁&rdquo;打架</strong></p></blockquote>
<p class="maodian"><a name="_label3"></a></p><h2>四、为什么 MyISAM 不需要意向锁?</h2>
<p class="maodian"><a name="_lab2_3_4"></a></p><h3>MyISAM 的锁模型</h3>
<ul><li>❌ 不支持行锁</li><li>✅ 只有表锁</li></ul>
<div class="jb51code"><pre class="brush:sql;">要么整张表读
要么整张表写
</pre></div>
<p>👉 不存在:</p>
<ul><li>行锁</li><li>表锁与行锁并存</li><li>自然 <strong>不需要意向锁</strong></li></ul>
<p class="maodian"><a name="_lab2_3_5"></a></p><h3>InnoDB 的优势(但更复杂)</h3>
<table><thead><tr><th>存储引擎</th><th>并发</th><th>锁模型</th></tr></thead><tbody><tr><td>MyISAM</td><td>低</td><td>表锁</td></tr><tr><td>InnoDB</td><td>高</td><td>行锁 + 意向锁</td></tr></tbody></table>
<p class="maodian"><a name="_label4"></a></p><h2>五、一个非常经典的死锁场景(面试常考)</h2>
<p class="maodian"><a name="_lab2_4_6"></a></p><h3>场景描述</h3>
<p>表 <code>user</code>:</p>
<table><thead><tr><th>id</th><th>name</th></tr></thead><tbody><tr><td>1</td><td>A</td></tr><tr><td>2</td><td>B</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_4_7"></a></p><h3>事务 A</h3>
<div class="jb51code"><pre class="brush:sql;">START TRANSACTION;
SELECT * FROM user WHERE id = 1 FOR UPDATE;
</pre></div>
<p>锁状态:</p>
<div class="jb51code"><pre class="brush:sql;">user 表:IX
id=1 行:X
</pre></div>
<p class="maodian"><a name="_lab2_4_8"></a></p><h3>事务 B</h3>
<div class="jb51code"><pre class="brush:sql;">START TRANSACTION;
LOCK TABLE user WRITE;
</pre></div>
<p>B 想要:</p>
<div class="jb51code"><pre class="brush:sql;">user 表:X
</pre></div>
<p>❌ 但被 A 的 <strong>IX</strong> 阻塞</p>
<p class="maodian"><a name="_lab2_4_9"></a></p><h3>接着事务 A 再做:</h3>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM user WHERE id = 2 FOR UPDATE;
</pre></div>
<p>此时:</p>
<ul><li>A 等待表锁释放</li><li>B 等待 IX 消失</li></ul>
<p>💥 <strong>死锁形成</strong></p>
<p>👉 InnoDB 会:</p>
<ul><li>自动检测</li><li>回滚其中一个事务</li></ul>
<p class="maodian"><a name="_label5"></a></p><h2>六、如何在生产中&ldquo;看到&rdquo;意向锁?</h2>
<p class="maodian"><a name="_lab2_5_10"></a></p><h3>1️⃣ 查看当前锁(MySQL 8.0)</h3>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM performance_schema.data_locks;
</pre></div>
<p>你会看到类似:</p>
<div class="jb51code"><pre class="brush:sql;">OBJECT_NAME = orders
LOCK_TYPE = TABLE
LOCK_MODE = IX
</pre></div>
<p class="maodian"><a name="_lab2_5_11"></a></p><h3>2️⃣ 常见 LOCK_MODE 含义</h3>
<table><thead><tr><th>LOCK_MODE</th><th>含义</th></tr></thead><tbody><tr><td>IS</td><td>意向共享</td></tr><tr><td>IX</td><td>意向排他</td></tr><tr><td>S</td><td>共享</td></tr><tr><td>X</td><td>排他</td></tr></tbody></table>
<p class="maodian"><a name="_label6"></a></p><h2>七、一句话总结</h2>
<blockquote><p><strong>意向锁是 InnoDB 自动维护的表级锁,用来声明事务将对表中的某些行加行锁,从而在加表锁时避免扫描所有行锁,是多粒度锁机制的关键。</strong></p></blockquote>
頁: [1]
查看完整版本: 一文搞懂MySQL 数据库意向锁