之前的学习中,一出现锁问题,我们都会通过一下两个命令之一来检测事务中的锁问题:
SHOW ENGINE INNODB STATUS;
SHOW FULL PROCESSLIST;
其实,MySQL为我们提供了更好的工具去记录和检测锁问题。大家还记得我们的数据库里有一个 information_schema数据库吗?
该数据库下面有3个重要的表(实际只有一张,其他两张已弃用),分别是:INNODB_TRX、INNODB_LOCKS(已弃用) 和 INNODB_LOCK_WAITS (已弃用) ,用于监控和诊断 InnoDB 引擎中锁与事务状态的系统表,常统称为 InnoDB 锁监控表。它们揭示了事务如何持有或等待锁,是排查锁等待和死锁问题的核心工具。
通过一张表格让大家简要理解一下这三张表:
表名 | 核心作用 | 关键字段/说明 | 状态 |
---|---|---|---|
INNODB_TRX | 提供当前所有活跃事务的详细信息。 | trx_id : 事务IDtrx_state : 事务状态 (e.g., RUNNING , LOCK WAIT )trx_started : 事务开始时间trx_mysql_thread_id : 关联的客户端连接IDtrx_query : 正在执行的SQL | 仍有效 |
INNODB_LOCKS | 显示当前事务已持有或正在申请的锁信息。 | lock_id : 锁IDlock_trx_id : 持有锁的事务IDlock_mode : 锁模式 (e.g., X , S )lock_type : 锁类型 (RECORD or TABLE )lock_table : 被锁定的表 | 已弃用 (MySQL 5.7+) 已移除 (MySQL 8.0+) |
INNODB_LOCK_WAITS | 揭示锁等待的阻塞关系。 | requesting_trx_id : 请求锁(被阻塞)的事务IDblocking_trx_id : 持有锁(阻塞他人)的事务ID | 已弃用 (MySQL 5.7+) 已移除 (MySQL 8.0+) |
下面举个例子说明这么查看INNODB_TRX表格:
犯错会吧:
准备两个窗口A、B;
有这么一张dotcpp_user表格:
进入A窗口,此时我们开启事务并对id>2的进行查询并“上锁”:
BEGIN; SELECT * FROM dotcpp_user WHERE id>2 FOR UPDATE;
进入B窗口,开启事务并插入一个新用户,(5,'dotcpp_user05','完全二叉树'),此时就等50s吧:
切换information_schema数据库后我们直接开始看表:
先看这张表INNODB_TRX:
mysql> select * from innodb_trx \G *************************** 1. row *************************** trx_id: 2432 trx_state: RUNNING trx_started: 2025-09-17 17:36:33 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 2 trx_mysql_thread_id: 46 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_lock_structs: 2 trx_lock_memory_bytes: 1128 trx_rows_locked: 3 trx_rows_modified: 0 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0 trx_is_read_only: 0 trx_autocommit_non_locking: 0 trx_schedule_weight: NULL 1 row in set (0.00 sec)
各参数解释如下:
字段 | 解释与分析 |
---|---|
trx_id | 事务ID:这个事务的内部编号是2432。 |
trx_state | 状态:最重要! 状态是RUNNING ,说明它是活跃的。它可能是阻塞者,而不是被阻塞者(如果是LOCK WAIT 就是被阻塞了)。 |
trx_started | 开始时间:这个事务已经开始运行了。可以根据这个时间判断它是不是一个“长事务”。 |
trx_requested_lock_id | 等待的锁:非常好! 这里是NULL ,表示这个事务没有在等待任何锁。它没有被其他事务阻塞。 |
trx_mysql_thread_id | 连接ID:非常关键! 这个ID可以直接关联到 SHOW PROCESSLIST 中的 Id 。下一步马上就用这个。 |
trx_query | 当前SQL:为NULL 表示事务当前没有在执行任何SQL语句。它处于“空闲”状态,很可能在等待应用程序发送下一条命令(比如 COMMIT )。 |
trx_rows_locked | 锁定行数:这个事务已经锁定了3行数据。这就是它可能成为“阻塞者”的原因。 |
trx_rows_modified | 修改行数:为0,表示这个事务还没有执行过 UPDATE /DELETE /INSERT 等修改操作。它是一个只读事务(但FOR UPDATE 读也会加锁)。 |
同时,我们通过SHOW FULL PROCESSLIST 语句查看MySQL当前所有的连接状态。该语句通常用来处理突发事件,返回的结果是实时变化的。
mysql> show full processlist;
+----+-----------------+-----------------+--------------------+---------+--------+------------------------+-----------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-----------------+-----------------+--------------------+---------+--------+------------------------+-----------------------+ | 5 | event_scheduler | localhost | NULL | Daemon | 176845 | Waiting on empty queue | NULL | | 19 | Dotcpp | localhost:51732 | dotcpp | Sleep | 11769 | | NULL | | 43 | Dotcpp | localhost:54206 | information_schema | Query | 0 | init | show full processlist | | 46 | Dotcpp | localhost:55737 | dotcpp | Sleep | 1137 | | NULL | +----+-----------------+-----------------+--------------------+---------+--------+------------------------+-----------------------+ 4 rows in set, 1 warning (0.00 sec)
列名 | 解释 |
---|---|
Id | MySQL服务器为每个客户端连接分配的唯一标识符。这就是之前在innodb_trx 里看到的trx_mysql_thread_id 。KILL 命令用的就是这个ID。 |
User | 建立此连接时使用的MySQL用户名。这里都是Dotcpp ,说明来自同一个应用。 |
Host | 显示客户端是从哪台机器的哪个端口连接的。格式为hostname:port 。- localhost:51732 :来自本机,操作系统分配的客户端端口是51732。- localhost:54206 :另一个连接,端口是54206。- localhost:55737 :第三个连接,端口是55737。 |
db | 连接当前正在使用的默认数据库。 - dotcpp :正在使用dotcpp 库。- information_schema :正在查询系统信息。- NULL :未选择数据库。 |
Command | 非常重要! 连接当前正在执行的命令类型。 - Sleep :连接处于空闲状态,等待客户端发送新命令。通常是事务未结束或连接池中的空闲连接。- Query :连接正在主动执行一个查询。- Daemon :MySQL服务器内部的系统守护线程(如事件调度器)。 |
Time | 非常重要! 当前状态已经持续的秒数。 - 对于 Sleep 命令,表示连接已经空闲了多久。- 对于 Query 命令,表示这个查询已经执行了多久。 |
State | 显示命令执行的详细状态(对于Query 命令尤其有用)。Sleep 状态的连接通常为空。init 表示正在初始化。 |
Info | 最关键的一列! 连接正在执行的SQL语句文本。如果为NULL ,则表示当前没有在执行SQL。- 对于 Sleep 状态的连接,这里显示的是它进入睡眠前最后执行的一条SQL。 |
结合表,我们得知:一个由连接46发起的事务(2432)已经开始了一段时间,它处于“空闲但持有锁”的状态。它自己没有被阻塞,但它手里紧紧抓着3行数据的锁不放,随时可能阻塞其他试图修改这些数据的事务。
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程