mysql锁机制是什么_mysql行锁与表锁区别

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

行锁和表锁不是“选哪个”,而是由引擎+语句+索引自动决定的

MySQL 本身不直接提供“手动切换行锁/表锁”的开关。锁类型由存储引擎、SQL 类型、是否命中索引共同触发:InnoDB 默认走行锁,但

UPDATE
DELETE
没走索引时会退化为表锁;MyISAM 则全程只用表锁,连
SELECT
都会自动加读锁。

查当前是否用了行锁?看执行计划:
EXPLAIN SELECT ... FOR UPDATE
key
字段非
NULL
rows
较小,大概率是行锁;若
type
ALL
key
NULL
,极可能升级为表锁
InnoDB 下,即使写了
WHERE id = ?
,如果
id
列没建索引,照样全表扫描 → 表锁
MyISAM 不支持事务,也不支持
SELECT ... FOR UPDATE
,强行写会报错:
ERROR 1036 (HY000): Table 'xxx' is read only

什么时候会意外拿到表锁?重点盯这三类操作

很多线上慢查询或阻塞,其实源于本想锁几行,结果锁了整张表——尤其在迁移 MyISAM 表到 InnoDB 后忽略索引设计时。

UPDATE
/
DELETE
语句中
WHERE
条件未命中任何索引(包括隐式类型转换,如
WHERE phone = 13800138000
phone
VARCHAR
对大字段(如
TEXT
BLOB
)做
ORDER BY
GROUP BY
,触发 filesort + 临时表,InnoDB 可能放弃行锁优化
显式使用
LOCK TABLES t1 WRITE
—— 这是强制表锁,哪怕你用的是 InnoDB,也会绕过 MVCC 直接上表级排他锁

如何验证当前锁行为?别只看文档,用真实命令看

光靠理论容易误判。InnoDB 提供了几个关键视图,比“应该加什么锁”更可信的是“实际加了什么锁”。

查当前锁等待:运行
SHOW ENGINE INNODB STATUS\G
,重点关注
TRANSACTIONS
LOCK WAIT
部分,能看到谁在等哪一行、被谁堵住
查最近死锁日志:同样在
SHOW ENGINE INNODB STATUS\G
输出末尾的
LATEST DETECTED DEADLOCK
区域,包含完整 SQL 和锁模式(
X
表示排他锁,
S
表示共享锁)
监控表锁争用:执行
SHOW GLOBAL STATUS LIKE 'table_locks%';
,若
table_locks_waited
持续增长,说明存在 MyISAM 表或 InnoDB 被迫升表锁的高频场景

行锁不是万能解药:它带来并发,也埋下死锁风险

行锁提升并发能力,但代价是锁管理更复杂。InnoDB 的行锁基于索引记录,而两个事务若以不同顺序访问相同几行,就极易触发死锁。

典型死锁链:
T1
先更新
id=1
再更新
id=2
T2
反过来先更新
id=2
再更新
id=1
→ 双方互相等待
避免方式:所有业务逻辑中,对多行更新务必按**主键/索引顺序**统一访问(比如总是
ORDER BY id ASC
),让加锁顺序一致
别依赖
SELECT ... FOR UPDATE
做“乐观重试”:它本质是悲观锁,一旦加锁失败(超时或死锁回滚),必须重试整个事务,而不是仅重试某条语句
行锁和表锁的边界从来不是非黑即白——真正影响系统的,往往是那条没走索引的
UPDATE
、那个忘记加
COMMIT
的事务、或是开发时以为“只是读一下”的
SELECT
却在 RR 隔离级别下触发了间隙锁。锁机制本身很稳,出问题的永远是人对它的假设。

相关推荐