在MySQL的日常运维和开发中,锁问题几乎是绕不开的话题。尤其是当某个事务长时间持有表锁,其他会话全部排队等待时,业务接口就会明显变慢甚至超时。这时候第一件事不是重启数据库,而是要搞清楚:到底是谁锁了这张表、锁了多久、锁的类型是什么。MySQL提供了多种查看表锁信息的方式,掌握它们可以让你在故障现场快速定位问题。

使用SHOW OPEN TABLES查看表的锁定状态
这是最直接的方式之一。SHOW OPEN TABLES会列出当前在表缓存中打开的表,其中有一列叫In_use,表示这张表当前被多少个线程使用(也就是正在等待或持有表级锁的会话数)。如果In_use大于1,通常说明存在并发争用。
-- 查看所有表的打开和使用状态 SHOW OPEN TABLES; -- 只看指定数据库的表 SHOW OPEN TABLES FROM mydb; -- 只看被锁定的表(In_use 大于 0) SHOW OPEN TABLES WHERE In_use > 0;
执行结果的几个关键列需要理解:Database是表所在的库,Table是表名,In_use表示当前正在使用该表的线程数量,Name_locked表示表名是否被锁定(通常只出现在DROP或RENAME操作期间)。当一张表的In_use值很高且持续不降,基本可以判断存在锁堆积。
需要注意的是,SHOW OPEN TABLES只能看到表级别的状态,无法告诉你具体是哪个会话、哪条SQL持有了锁。它更像一个预警指标,具体溯源还需要结合下面的方法。
通过SHOW PROCESSLIST定位阻塞会话
当确认有表被锁定后,下一步就是找到持锁的会话。SHOW PROCESSLIST(或查询information_schema.PROCESSLIST)会列出所有连接的状态,重点观察Command和Time列。
-- 查看当前所有会话 SHOW FULL PROCESSLIST; -- 从系统表中查询,便于过滤 SELECT id, user, host, db, command, time, state, info FROM information_schema.PROCESSLIST WHERE command != 'Sleep' ORDER BY time DESC;
典型的锁等待场景是这样的:某个会话执行了一条LOCK TABLES或长事务未提交,状态显示为Sleep但Time很大;而其他会话的State列显示Waiting for table metadata lock或Waiting for table level lock,这些就是被阻塞的会话。找到了长时间Sleep且持有事务的会话id,就可以进一步处理。
如果拥有PROCESS权限,可以看到完整的SQL文本,这对判断持锁事务在做什么非常有帮助。对于被阻塞的会话,通常不建议直接杀掉,而是优先处理阻塞源头。
利用information_schema查询锁与事务详情
MySQL 5.7及之前的版本中,information_schema.INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS三张表组合可以还原完整的锁等待关系。MySQL 8.0做了调整,锁相关的表迁移到了performance_schema下,改名为data_locks和data_lock_waits。
-- MySQL 5.7:查看当前所有事务及锁等待
SELECT * FROM information_schema.INNODB_TRX;
SELECT * FROM information_schema.INNODB_LOCK_WAITS
WHERE requesting_trx_id != blocking_trx_id;
-- MySQL 8.0:通过 performance_schema 查看锁等待链
SELECT * FROM performance_schema.data_locks
WHERE OBJECT_NAME = 'my_table';
SELECT r.trx_id AS waiting_trx, r.trx_mysql_thread_id AS waiting_thread,
b.trx_id AS blocking_trx, b.trx_mysql_thread_id AS blocking_thread
FROM performance_schema.data_lock_waits w
JOIN information_schema.INNODB_TRX b ON b.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID
JOIN information_schema.INNODB_TRX r ON r.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID;
INNODB_TRX中的trx_started和trx_mysql_thread_id两个字段最有价值,前者告诉你事务开始了多久,后者可以直接对应到SHOW PROCESSLIST中的线程id,从而定位到具体的连接。
还要提醒一点:这些表主要针对InnoDB的行锁和意向锁。表级锁中比较特殊的是元数据锁(MDL),它无法通过data_locks直接查看,需要开启performance_schema的mdl instruments后查询metadata_locks表才能看到。
解锁操作与排查建议
找到阻塞源头后,如果确认该会话可以终止,使用KILL命令即可释放锁:
-- 杀掉指定会话,id 来自 SHOW PROCESSLIST KILL 12345; -- 只终止当前正在执行的语句,保留连接和事务 KILL QUERY 12345;
KILL会回滚该会话未提交的事务并释放其持有的所有锁;KILL QUERY则温和一些,只终止当前语句。对于不确定是否可以杀的业务连接,先与业务方确认,避免误伤正在执行的关键操作。
从预防角度看,表锁问题大多来自几个习惯:事务中夹杂耗时操作导致长时间不提交、使用LOCK TABLES后忘记解锁、在业务高峰期执行DDL引发MDL排队。建议尽量缩短事务长度,避免在事务里做RPC调用或大量计算;执行DDL前先用SHOW PROCESSLIST确认没有长事务;必要时设置lock_wait_timeout和innodb_lock_wait_timeout,让等待锁的会话尽快失败而不是无限堆积。把以上几种查看手段组合使用,绝大多数表锁问题都能在几分钟内定位到源头。
mysql表锁SHOW OPEN TABLESinformation_schema修改时间:2026-09-13 15:54:40