mysql锁是什么_mysql锁基础概念解析

来源:这里教程网 时间:2026-02-28 20:48:30 作者:

MySQL锁是事务并发访问数据时,为保证一致性而强制施加的访问控制机制——不是可选功能,而是InnoDB默认启用的底层保障。

行锁为什么只锁索引,不锁“数据行”本身?

因为InnoDB的行锁本质是

record lock
,它加在**索引记录上**,而非磁盘上的物理行。哪怕你没建任何索引,InnoDB也会生成隐藏聚簇索引(
GEN_CLUST_INDEX
),所有行锁都落在这棵B+树的叶子节点上。

用主键更新:
UPDATE user SET name='A' WHERE id=100
→ 只在聚簇索引
id=100
处加X锁
用二级索引更新:
UPDATE user SET age=25 WHERE name='Tom'
→ 先在
name='Tom'
的二级索引项加X锁,再回表到聚簇索引
id=xxx
加X锁(两处都要锁)
没索引条件查询:
UPDATE user SET status=1 WHERE phone LIKE '%123%'
→ 无法走索引,InnoDB退化为对**所有索引记录**加锁,实际效果≈表锁

共享锁(S)和排他锁(X)到底怎么互斥?

不是“读写不能并存”这么简单,关键是看锁类型组合是否兼容。InnoDB按标准规则判定:

S
S
:✅ 兼容 → 多个事务可同时
SELECT ... LOCK IN SHARE MODE
S
X
X
S
X
X
:❌ 不兼容 → 任一事务持有X锁,其他事务连S锁都申请不到
意向锁(
IS
/
IX
)自动伴随出现:比如事务要对某行加X锁,会先在表级加
IX
锁,避免其他事务对整张表加
X
表锁冲突

常见误判:以为

SELECT ... FOR UPDATE
只锁查到的行——其实它还会触发
gap lock
next-key lock
(尤其在
REPEATABLE READ
下),可能锁住相邻间隙,防止幻读。

什么时候会从行锁“升级”成表锁?

不是主动升级,而是**因缺失有效索引被迫全表扫描+全索引加锁**,导致事实上的表级阻塞。典型场景包括:

WHERE条件字段无索引,且执行
UPDATE
/
DELETE
(InnoDB必须遍历所有索引记录,逐个加X锁)
显式使用
LOCK TABLES t1 WRITE
(MyISAM常用,InnoDB中应尽量避免)
隐式MDL锁竞争:当一个长事务正在执行
SELECT
,另一个线程试图
ALTER TABLE
,后者会被阻塞在MDL写锁上——这不是数据锁,但效果类似表不可写

验证是否发生表级争用:

SHOW STATUS LIKE 'Table_locks_waited'
值持续上升,说明有大量线程在等表锁。

真正容易被忽略的是:锁的生命周期绑定事务,

COMMIT
ROLLBACK
才释放;而MVCC只解决“读不加锁”,一旦涉及修改(哪怕只是
SELECT ... FOR UPDATE
),锁就立刻生效——别以为开了
READ COMMITTED
就能绕过锁冲突。

相关推荐