在MySQL InnoDB存储引擎的并发场景中,锁等待、死锁等问题往往会导致业务响应缓慢甚至服务不可用。掌握高效的锁监控与排查方法,是数据库运维和开发人员的核心技能之一。本文将基于实战实验,详细介绍5种常用的InnoDB锁信息获取方式,帮助你快速定位和解决锁相关问题。
实验环境准备
为了保证所有实验可复现,我们首先创建统一的测试表和数据。以下SQL语句将在martin数据库中创建表t19,并插入1条测试数据:
sql
use martin;
-- 若表已存在则删除,避免干扰
drop table if exists t19;
CREATE TABLE `t19` (
`id` int NOT NULL AUTO_INCREMENT,
`a` int NOT NULL,
`b` int NOT NULL,
`c` int NOT NULL,
PRIMARY KEY (`id`), -- 主键索引
KEY `idx_a` (`a`) -- 普通索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入测试数据
insert into t19(a,b,c) values(1,1,1);
所有实验均基于3个数据库会话(session1、session2、session3) 模拟并发场景,通过不同会话的事务操作触发锁等待,再用对应的工具排查锁信息。
一、show processlist:快速定位锁等待线程
show processlist是最基础的锁排查命令,能快速查看当前数据库所有线程的状态,包括是否存在锁等待。它的优势是轻量、执行速度快,适合初步排查。
实验步骤
| 步骤 | session1(事务1) | session2(事务2) | session3(监控会话) |
|---|---|---|---|
| 1 | begin;(开启事务) |
begin;(开启事务) |
- |
| 2 | update t19 set b=2 where a=1;(更新数据,加锁) |
- | - |
| 3 | - | update t19 set b=3 where a=1;(同条件更新,触发锁等待) |
show processlist;(查看线程状态) |
| 4 | commit;(提交事务,释放锁) |
commit;(提交事务) |
- |
结果分析
执行show processlist;后,会看到类似以下关键信息:

列含义说明
- Id:连接的唯一标识。
- User:执行该连接的数据库用户。
- Host:连接来自的主机。
- db:当前连接操作的数据库。
- Command:当前执行的命令类型,如查询(Query)、守护进程(Daemon)、睡眠(Sleep)等。
- Time:该操作已执行的时间(秒)。
- State:操作的当前状态。
- Info:具体的SQL语句(若有)。
逐行解析
-
第一行(Id=5)
- User:
event_scheduler,这是MySQL的事件调度器进程,用于执行定时任务。 - Command:
Daemon,表示这是一个守护进程。 - Time:
1195880秒,说明该进程已运行很久。 - State:
Waiting on empty queue,表示当前没有待执行的事件,处于空闲等待状态。 - Info:
NULL,因为它不是执行SQL查询的连接。
- User:
-
第二行(Id=111)
- User:
root,是数据库的管理员用户。 - Command:
Query,表示正在执行SQL查询。 - Time:
10秒,该更新操作已执行10秒。 - State:
updating,说明正在更新表数据。 - Info:
update t19 set b=3 where a=1,具体的更新SQL语句,对t19表中a=1的行设置b=3。
- User:
-
第三行(Id=112)
- User:
root。 - Command:
Query。 - Time:
0秒,刚执行。 - State:
init,表示查询初始化阶段。 - Info:
show processlist,就是当前执行的这条查看进程列表的SQL语句。
- User:
-
第四行(Id=113)
- User:
root。 - Command:
Sleep,表示该连接处于空闲睡眠状态。 - Time:
15秒,空闲了15秒。 - Info:
NULL,没有执行SQL语句。
- User:
通过这些信息,我们可以了解 MySQL 当前的连接和执行情况,比如识别长时间运行的查询、空闲连接等信息,适合作为"第一步排查工具"。
二、information_schema.innodb_trx:查看活跃事务详情
innodb_trx是InnoDB内置的系统表,存储了当前所有活跃事务 (未提交的事务)的详细信息,包括事务ID、状态、等待开始时间等。相比show processlist,它能提供更深入的事务级信息。
实验步骤
| 步骤 | session1(事务1) | session2(事务2) | session3(监控会话) |
|---|---|---|---|
| 1 | begin;(开启事务) |
- | - |
| 2 | update t19 set b=2 where a=1;(加锁) |
update t19 set b=3 where a=1;(触发锁等待) |
select * from information_schema.innodb_trx\G(查看事务详情) |
| 3 | commit;(释放锁) |
- | - |
关键字段解释
使用\G格式化输出(避免列过多导致混乱),重点关注以下字段:
trx_id:事务ID(InnoDB内部标识);trx_state:事务状态(如LOCK WAIT表示锁等待,RUNNING表示正常运行);trx_wait_started:锁等待开始时间(可用于判断等待时长);trx_mysql_thread_id:对应MySQL的线程ID(可关联show processlist的Id字段);trx_query:事务当前执行的SQL语句。
结果分析

从输出结果中可明确:
- session2的
trx_state为LOCK WAIT,且trx_query为更新t19的SQL; - session1的
trx_state为RUNNING,持有锁且未提交; - 通过
trx_wait_started可计算等待时间,判断是否为"长时间阻塞"。
该表适合深入分析事务状态,但无法直接查看锁的类型和关联关系。
三、performance_schema.data_locks:查看具体锁信息
data_locks是MySQL 5.7+引入的性能_schema表,用于存储当前所有已获取或等待的锁的详细信息,包括锁类型、锁模式、关联的表/索引等。它是排查"锁是什么"的核心工具。
实验步骤
| 步骤 | session1(事务1) | session2(监控会话) |
|---|---|---|
| 1 | begin;(开启事务) |
- |
| 2 | update t19 set b=2 where a=1;(加锁) |
SELECT * FROM performance_schema.data_locks\G(查看锁信息) |
| 3 | commit;(释放锁) |
- |
关键字段解释
LOCK_TYPE:锁类型(TABLE表示表锁,RECORD表示行锁);LOCK_MODE:锁模式(如X表示排他锁,S表示共享锁,IX表示意向排他锁);LOCK_TABLE:被锁的表(格式为数据库名.表名);LOCK_INDEX:被锁的索引(如idx_a表示基于普通索引加锁,PRIMARY表示基于主键索引);LOCK_DATA:被锁的具体数据(行锁时显示主键值,表锁时为NULL);THREAD_ID:持有锁的线程ID;LOCK_STATUS:锁状态(GRANTED表示已获取,WAITING表示等待)。
结果分析

本次实验中,session1执行update后,data_locks会输出两条关键记录:
- 表级意向排他锁(IX) :
LOCK_TYPE=TABLE,LOCK_MODE=IX,LOCK_TABLE=martin.t19。InnoDB在加行锁前会先加表级意向锁,避免表锁与行锁冲突; - 行级排他锁(X) :
LOCK_TYPE=RECORD,LOCK_INDEX=idx_a,LOCK_DATA=1(a=1对应的行),LOCK_MODE=X。这是实际阻塞session2的锁。
通过该表,我们能清晰知道"谁持有什么类型的锁",为后续排查锁冲突原因提供关键依据。
四、performance_schema.data_lock_waits:分析锁等待关系
data_lock_waits表存储了锁等待的关联关系,即"哪个线程在等哪个线程的锁"。它能直接建立"等待方"和"持有方"的关联,是排查"谁阻塞了谁"的核心工具。
实验步骤
| 步骤 | session1(事务1) | session2(事务2) | session3(监控会话) |
|---|---|---|---|
| 1 | begin;(开启事务) |
begin;(开启事务) |
- |
| 2 | update t19 set b=3 where a=1;(加锁) |
- | - |
| 3 | - | update t19 set b=4 where a=1;(触发锁等待) |
select * from performance_schema.data_lock_waits\G(查看锁等待关系) |
| 4 | commit;(释放锁) |
commit;(提交事务) |
- |
关键字段解释
REQUESTING_THREAD_ID:请求锁的线程ID(等待方);BLOCKING_THREAD_ID:持有锁的线程ID(阻塞方);REQUESTED_LOCK_ID:请求的锁ID(可关联data_locks的LOCK_ID);BLOCKING_LOCK_ID:阻塞的锁ID(可关联data_locks的LOCK_ID)。
进阶:查询阻塞/请求锁的SQL语句
通过data_lock_waits关联events_statements_current表(存储当前线程执行的SQL),可直接获取阻塞方和请求方的具体SQL,无需手动关联线程ID。
1. 查找"持有阻塞锁的事务"执行的SQL
sql
SELECT esc.sql_text
FROM performance_schema.data_lock_waits dlw
JOIN performance_schema.events_statements_current esc
ON dlw.BLOCKING_THREAD_ID = esc.thread_id;
该语句会返回阻塞方(如session1)执行的update t19 set b=3 where a=1;。
2. 查找"请求锁的事务"执行的SQL
sql
SELECT esc.sql_text
FROM performance_schema.data_lock_waits dlw
JOIN performance_schema.events_statements_current esc
ON dlw.REQUESTING_THREAD_ID = esc.thread_id;
该语句会返回等待方(如session2)执行的update t19 set b=4 where a=1;。
结果分析
data_lock_waits的输出会明确:
-
session2(
REQUESTING_THREAD_ID)在等待session1(BLOCKING_THREAD_ID)的锁;

-
结合关联SQL查询,可直接定位到导致阻塞的具体SQL语句,无需逐个排查线程。


该表是锁等待根源定位 的关键,建议与data_locks配合使用(通过LOCK_ID关联锁详情)。
五、其他补充:特殊场景的锁排查方法
除了上述4种核心方法,还有3种工具适用于特殊场景(如死锁、元数据锁)。
1. show engine innodb status:获取死锁详情
当数据库发生死锁时,InnoDB会自动回滚其中一个事务,但死锁信息不会存储在系统表中,需通过show engine innodb status;实时查看。
用法
直接执行命令,在输出结果的LATEST DETECTED DEADLOCK部分,会显示:
- 死锁发生的时间;
- 参与死锁的两个事务的ID、SQL语句;
- 每个事务持有和等待的锁类型;
- 被回滚的事务ID。

适用场景
死锁排查(死锁后快速获取原因,避免重复发生)。
2. performance_schema.metadata_locks:查看元数据锁
元数据锁(MDL锁)用于保护表结构的修改(如ALTER TABLE),避免"表结构修改"与"增删改查"并发冲突。metadata_locks表存储了当前所有元数据锁的信息。
用法
sql
select * from performance_schema.metadata_locks;
关键字段
OBJECT_TYPE:对象类型(TABLE表示表级元数据锁);OBJECT_SCHEMA:数据库名;OBJECT_NAME:表名;LOCK_TYPE:锁类型(如SHARED_READ表示读元数据锁,EXCLUSIVE表示排他元数据锁);LOCK_STATUS:锁状态(GRANTED或WAITING)。

适用场景
表结构修改阻塞排查 (如ALTER TABLE卡住时,查看是否有查询持有读元数据锁)。
3. performance_schema.table_handles:查看表句柄信息
table_handles表存储了当前所有线程打开的表句柄(InnoDB对表的内部引用)信息,可用于判断哪些线程正在操作某个表。
用法
sql
select * from performance_schema.table_handles limit 2\G;
关键字段
OWNER_THREAD_ID:操作表的线程ID;OBJECT_SCHEMA:数据库名;OBJECT_NAME:表名;OBJECT_INSTANCE_BEGIN:对象实例起始标识;EVENT_ID:事件 ID。

适用场景
表级资源占用排查(如判断某个表是否被大量线程占用,导致性能下降)。
总结:锁排查流程建议
在实际工作中,建议按照"从粗到细"的流程排查锁问题:
- 初步定位 :用
show processlist判断是否存在锁等待,以及等待的线程ID; - 事务分析 :用
information_schema.innodb_trx查看等待线程的事务状态、等待时长和执行SQL; - 锁详情查询 :用
performance_schema.data_locks查看持有/等待的锁类型、关联的索引和数据; - 锁等待关系 :用
performance_schema.data_lock_waits关联阻塞方和等待方,定位根源SQL; - 特殊场景 :死锁用
show engine innodb status,元数据锁用metadata_locks,表句柄用table_handles。
通过以上方法,可高效解决InnoDB并发场景中的锁等待、死锁等问题,保障数据库服务的稳定运行。