mysql中的锁机制:行级锁与表级锁

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

行级锁只在 InnoDB 有效,MyISAM 根本不支持

MySQL 的锁机制和存储引擎强绑定。InnoDB 支持行级锁(

SELECT ... FOR UPDATE
UPDATE
DELETE
等语句默认加行锁),而 MyISAM 只支持表级锁(所有 DML 操作都锁整张表)。如果你执行了
SELECT ... FOR UPDATE
却没生效——先查
SHOW CREATE TABLE tbl_name
,确认引擎是不是
ENGINE=InnoDB

常见错误现象:

在 MyISAM 表上执行
SELECT ... FOR UPDATE
不报错,但实际无锁效果(语句成功,锁未建立)
事务中更新某几行后,其他事务仍能修改同一张 MyISAM 表的任意行(因为根本没行锁) 误以为加了索引就自动用行锁——其实 InnoDB 行锁是加在索引记录上的,若
WHERE
条件无法命中索引,会退化为表级锁(锁全表所有索引项,等效于锁表)

行锁不是“锁住某行数据”,而是锁住索引记录

InnoDB 的行级锁本质是锁住聚簇索引或二级索引中的记录。这意味着:

UPDATE users SET name='a' WHERE id = 100
:如果
id
是主键,则锁住聚簇索引中
id=100
的那条记录
UPDATE users SET name='a' WHERE email='x@y.z'
:如果
email
有唯一索引,则锁住该二级索引记录 + 对应的聚簇索引记录(next-key lock)
UPDATE users SET name='a' WHERE status = 1
:若
status
无索引,InnoDB 会扫描全表,对每条匹配记录加锁,同时可能触发间隙锁(gap lock)或临键锁(next-key lock),导致大量无关行被锁定

容易踩的坑:用

EXPLAIN
看执行计划,确认
type
是否为
const
/
ref
;如果是
ALL
index
,大概率已丧失行锁粒度。

表级锁不只是 LOCK TABLES,隐式锁更常见

显式表锁(

LOCK TABLES t1 WRITE
)极少在业务代码中使用,但隐式表级锁频繁出现:

ALTER TABLE
在大多数 MySQL 版本中会获取元数据锁(MDL),阻塞后续 DML,本质是表级协调锁
MyISAM 执行
INSERT
时自动加表写锁,此时任何读(
SELECT
)都会等待
InnoDB 在某些 DDL 场景下(如无
ALGORITHM=INPLACE
的列添加)也会升级为表级锁
FLUSH TABLES WITH READ LOCK
是全局表级读锁,常用于物理备份,但会阻塞所有写入

性能影响明显:一个慢

ALTER TABLE
可能让整个库的写请求排队,监控时注意
show processlist
中状态为
Waiting for table metadata lock
的线程。

死锁检测与日志怎么看

InnoDB 死锁检测是自动开启的(

innodb_deadlock_detect=ON
),一旦发生,MySQL 会选一个事务回滚并返回错误:

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

要定位原因,必须开死锁日志:

设置
innodb_print_all_deadlocks = ON
(写入 error log,非实时输出)
或执行
SHOW ENGINE INNODB STATUS\G
,查看
LATEST DETECTED DEADLOCK
区域

日志里关键信息包括:

每个事务持有的锁(
HELD LOCKS
正在等待的锁(
WAITING FOR THIS LOCK TO BE GRANTED
涉及的表名、索引名、具体记录的主键值(如
space id 123 page no 1024 n bits 72
后跟
record lock, heap no 5

真正难处理的是“锁等待链过长”而非死锁:比如事务 A 锁住行 X,事务 B 等 A;B 又锁住行 Y,事务 C 等 B……这种不会触发死锁检测,但会导致请求堆积,需靠

information_schema.INNODB_TRX
INNODB_LOCK_WAITS
关联分析。

相关推荐