MySQL UPDATE 语句加锁机制解析(基于 InnoDB 引擎)
1. UPDATE 语句涉及的锁类型
在 InnoDB 存储引擎中,UPDATE 语句主要涉及以下几种锁:
| 锁类型 | 作用范围 | 作用说明 |
|---|---|---|
| 行锁(Record Lock) | 具体的行 | 锁住被 UPDATE 修改的行,防止其他事务修改该行。 |
| 间隙锁(Gap Lock) | 行记录之间的索引区间 | 锁住查询范围内的“间隙”,防止其他事务插入新记录(仅 REPEATABLE READ 级别会用到)。 |
| 临键锁(Next-Key Lock) | 行锁 + 间隙锁 | REPEATABLE READ 级别下默认行为,锁住索引记录及其间隙,防止幻读。 |
| 意向排他锁(IX Lock) | 整张表 | 表示事务即将在某些行上加 X 锁,不会阻塞其他事务的行级锁,但会影响表级锁。 |
2. UPDATE 语句的加锁细节
(1)单行更新
UPDATE user SET age = 30 WHERE id = 1;
加锁行为:
-
行锁(Record Lock):锁住
id=1这行,防止其他事务修改。 -
意向排他锁(IX):在
user表上添加 IX 锁,不会影响其他事务查询和更新不同的行。
示例:
-
事务A:
START TRANSACTION; UPDATE user SET age = 30 WHERE id = 1; -- 事务A锁住了 id=1 这一行 -
事务B(尝试更新相同的行,阻塞):
UPDATE user SET age = 40 WHERE id = 1; -- 事务A未提交时,事务B会被阻塞
(2)范围更新(WHERE 条件命中多行)
UPDATE user SET age = 30 WHERE age > 20;
加锁行为(REPEATABLE READ 级别):
-
行锁(Record Lock):锁住所有
age > 20的记录。 -
间隙锁(Gap Lock):锁住
age=20之后的索引区间,防止其他事务插入新行。 -
临键锁(Next-Key Lock)(默认开启):
-
既锁住已有的行,也锁住
age > 20之间的间隙,防止幻读。 -
如果事务 B 试图插入
age=25,会被阻塞。
-
(3)无索引条件更新
UPDATE user SET age = 30 WHERE name = 'Alice';
加锁行为(InnoDB 无合适索引时):
-
全表扫描:MySQL 需要扫描整张表找
name='Alice',导致行锁升级为表锁! -
表锁(Table Lock):阻塞所有对该表的写操作,极大降低并发性能。
优化方案:
ALTER TABLE user ADD INDEX idx_name (name);
加索引后,只锁 name='Alice' 的记录,而不是整张表。
3. 不同隔离级别对 UPDATE 加锁的影响
| 隔离级别 | 行锁 | 间隙锁 | Next-Key Lock |
|---|---|---|---|
| READ UNCOMMITTED | ✅ | ❌ | ❌ |
| READ COMMITTED | ✅ | ❌ | ❌ |
| REPEATABLE READ(默认) | ✅ | ✅ | ✅ |
| SERIALIZABLE | ✅ | ✅ | ✅(甚至可能升级为表锁) |
-
READ COMMITTED:仅对实际匹配的行加行锁,不会加间隙锁,不会防止幻读。
-
REPEATABLE READ:默认使用 Next-Key Lock(行锁+间隙锁),可防止幻读。
-
SERIALIZABLE:可能升级为表级锁,完全阻止并发写入。
4. 死锁风险
当两个事务同时更新不同的记录时,如果获取锁的顺序不同,可能发生死锁。
示例:
-- 事务 A
START TRANSACTION;
UPDATE user SET age = 30 WHERE id = 1;
UPDATE user SET age = 40 WHERE id = 2; -- 这里可能被事务 B 锁住
-- 事务 B(反向顺序)
START TRANSACTION;
UPDATE user SET age = 40 WHERE id = 2;
UPDATE user SET age = 30 WHERE id = 1; -- 这里可能被事务 A 锁住,形成死锁
解决方案:
-
始终按照相同顺序更新记录
-
合理使用索引,避免锁表
-
SHOW ENGINE INNODB STATUS分析死锁
5. 关键总结
-
UPDATE 语句会加:
-
行锁(防止其他事务修改相同行)。
-
间隙锁(防止插入,避免幻读)。
-
Next-Key Lock(行锁+间隙锁,REPEATABLE READ 默认)。
-
意向排他锁(IX)(保证表锁和行锁协调)。
-
-
索引影响加锁范围:
-
有索引时,只锁定命中的行。
-
无索引时,可能锁全表(导致性能下降)。
-
-
不同隔离级别影响加锁策略:
-
READ COMMITTED 仅加行锁,不加间隙锁。
-
REPEATABLE READ 默认启用 Next-Key Lock 以防止幻读。
-
-
死锁处理:
-
事务必须按相同顺序更新数据,避免死锁。
-
可使用
SHOW ENGINE INNODB STATUS分析死锁原因。
-
这些机制确保 UPDATE 操作在高并发环境下既能保证一致性,又能尽量减少性能损耗。

2391

被折叠的 条评论
为什么被折叠?



