在mysql数据库的日常运维和开发过程中,锁等待是引发业务性能下降的常见原因,当多个事务同时操作同一批数据且加锁顺序不一致时,就可能出现锁等待甚至死锁的情况。分析锁等待日志是定位这类问题最直接有效的方式,通过日志可以清晰看到等待的事务、持有的锁资源以及阻塞的SQL语句等关键信息。

开启mysql锁等待日志
mysql的InnoDB引擎默认不会主动输出详细的锁等待日志,需要手动开启相关监控功能。最常用的是开启innodb_lock_monitor功能,开启后InnoDB会定期将锁相关的信息输出到mysql的错误日志中。
开启方式分为临时开启和永久开启两种:
临时开启(重启后失效)
直接在mysql客户端执行如下SQL即可开启:
-- 开启InnoDB锁监控 CREATE TABLE innodb_lock_monitor (a INT) ENGINE=INNODB; -- 确认是否开启成功 SHOW ENGINE INNODB STATUSG
如果要关闭临时开启的锁监控,执行如下SQL:
DROP TABLE innodb_lock_monitor;
永久开启(重启后生效)
修改mysql的配置文件my.cnf(或my.ini),在[mysqld]配置段下添加如下配置:
[mysqld] innodb_monitor_enable=all
修改完成后重启mysql服务即可生效,这种方式会在错误日志中持续输出锁相关的监控信息。
锁等待日志的获取方式
除了开启锁监控输出到错误日志外,还可以通过系统命令和表直接获取实时的锁等待信息,两种方式结合使用效率更高。
通过SHOW ENGINE命令获取
执行如下命令可以获取当前InnoDB引擎的状态信息,其中包含锁等待的相关内容:
SHOW ENGINE INNODB STATUSG
该命令输出的内容较多,我们需要重点关注TRANSACTIONS和LATEST DETECTED DEADLOCK两个段落,前者包含当前活跃事务的锁等待情况,后者包含最近检测到的死锁信息。
通过系统表查询
mysql 8.0及以上版本提供了performance_schema库下的锁相关系统表,可以直接查询实时的锁等待信息,常用的表如下:
data_locks:记录当前所有持有的锁和等待的锁信息data_lock_waits:记录当前锁等待的关联关系innodb_trx:记录当前所有活跃的事务信息
可以通过如下SQL关联查询当前的锁等待情况:
SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, r.trx_query AS waiting_query, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, b.trx_query AS blocking_query FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
锁等待日志内容解读
当我们获取到锁等待日志后,需要能够正确解读其中的关键信息,才能快速定位问题。以下是一段典型的锁等待日志片段:
---TRANSACTIONS--- Trx id counter 42123123 Purge done for trx's n:o < 42123120 undo n:o < 0 state: running but idle History list length 34 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 42123122, ACTIVE 10 sec 2 lock struct(s), heap size 1136, 1 row lock(s) MySQL thread id 12, OS thread handle 140123456789, query id 123 localhost root Sending data SELECT * FROM user WHERE id = 1 FOR UPDATE ---TRANSACTION 42123121, ACTIVE 20 sec 2 lock struct(s), heap size 1136, 1 row lock(s) MySQL thread id 11, OS thread handle 140123456788, query id 122 localhost root Waiting for table metadata lock UPDATE user SET name = 'test' WHERE id = 1
这段日志中的关键信息解读如下:
Trx id:事务的唯一ID,用于区分不同的事务ACTIVE 10 sec:事务处于活跃状态的时间,时间越长越容易引发问题lock struct(s):事务持有的锁结构数量row lock(s):事务持有的行锁数量MySQL thread id:对应mysql的线程ID,可以通过SHOW PROCESSLIST命令查看该线程的详细信息query id:当前执行的SQL的IDWaiting for table metadata lock:表示当前事务正在等待表元数据锁,也就是被其他事务阻塞了
锁等待问题的定位与处理
结合锁等待日志和系统表信息,可以按照如下步骤定位和处理锁等待问题:
第一步:找到阻塞源头事务
通过前面提到的关联查询SQL,找到blocking_trx_id对应的阻塞事务,再通过SHOW PROCESSLIST查看该线程的执行状态:
SHOW PROCESSLIST;
如果阻塞事务处于Sleep状态且长时间没有执行新的SQL,说明该事务没有及时提交,占用了锁资源。
第二步:确认阻塞事务的SQL
如果阻塞事务的trx_query字段为空,说明该事务当前没有正在执行的SQL,但是之前执行的SQL持有的锁还没有释放,可以通过SHOW ENGINE INNODB STATUSG查看该事务的历史SQL。
第三步:处理锁等待问题
定位到阻塞源头后,可以根据实际情况选择处理方式:
- 如果是事务没有及时提交,可以联系业务方提交事务,或者手动执行
KILL [线程ID]命令结束阻塞事务 - 如果是SQL语句的加锁范围过大,比如没有走索引导致锁全表,需要优化SQL语句,添加合适的索引
- 如果是业务逻辑中的加锁顺序不一致,需要调整业务代码中的事务加锁顺序,避免交叉加锁
锁等待日志分析的注意事项
在分析锁等待日志时,需要注意以下几点:
- 开启锁监控后,错误日志会增长较快,建议在排查问题时临时开启,排查完成后及时关闭
- mysql 5.7及以下版本的系统表和8.0版本有部分差异,查询时需要注意版本对应的表结构
- 锁等待日志中的事务ID是动态的,每次重启mysql后事务ID会重新计数,分析时需要结合时间戳判断
- 对于偶发的锁等待问题,可以结合慢查询日志一起分析,确认是否有慢SQL导致事务长时间持有锁
注意:生产环境执行KILL命令结束事务时,需要确认该事务没有执行重要的业务操作,避免数据不一致问题。
mysql锁等待锁等待日志innodb_lock_monitor修改时间:2026-07-01 00:18:38