应先查INNODB_TRX和INNODB_LOCK_WAITS定位阻塞源,KILL BLOCKING_TRX_ID对应线程;调大innodb_lock_wait_timeout仅延迟失败,不解决锁持有问题,需结合索引优化、事务粒度控制和死锁日志分析根治。

直接查 INNODB_TRX 和 INNODB_LOCK_WAITS 就行,不用翻错误日志
MySQL 的 “Lock wait timeout exceeded” 不会单独记进错误日志(error.log)里——它只是客户端收到的 SQL 错误响应,服务端不落盘。所以你去翻 /var/log/mysql/error.log 或 mysqld.err,大概率找不到这句。真正能实时看到谁在等、谁在卡的,是内存里的系统视图。
执行这两条语句就能定位问题:
-
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'LOCK WAIT';→ 找出正在等锁的事务,记下它的trx_id和trx_mysql_thread_id -
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;→ 关联出blocking_trx_id,也就是真正持锁不放的那个事务 ID
注意:INNODB_LOCK_WAITS 在 MySQL 8.0+ 中字段更友好,比如直接有 waiting_pid 和 blocking_pid;5.7 则需手动 JOIN INNODB_TRX 补全信息。
SHOW ENGINE INNODB STATUS\G 里藏了关键上下文
这条命令输出很长,但对锁等待超时特别有用的部分在 TRANSACTIONS 区块,不是 LATEST DETECTED DEADLOCK(那是死锁专用)。你需要手动翻到 “---TRANSACTION” 开头的段落,重点关注:
- 状态为
LOCK WAIT的事务,它下面会写明mysql thread id、query id和正在执行的 SQL - 紧接着一行通常有
holds the lock(s)或waiting for this lock to be granted,能帮你确认锁类型(如X RECORD LOCKS)和锁定的具体索引值(lock_data: 123) - 如果看到某个事务
TRX_STATE = RUNNING且TRX_STARTED是几分钟前,但TRX_QUERY为空,基本就是应用端开了事务没提交,挂在那里占着锁
别信 wait_timeout,要看 innodb_lock_wait_timeout
很多人搜错参数,把连接空闲超时(wait_timeout)和锁等待超时(innodb_lock_wait_timeout)混了。后者才是决定“等多久就报 Lock wait timeout exceeded”的那个值:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 查当前值:
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';(默认 50 秒) - 这个值只影响 DML(
UPDATE/DELETE/SELECT ... FOR UPDATE)的行锁等待,不影响 DDL - 线上调低到 30 秒可以更快暴露问题,但不能解决根本原因;设太高(比如 120)会让业务线程卡得更久,拖垮整体吞吐
改完记得 SET GLOBAL innodb_lock_wait_timeout = 30;,但要注意该变量不支持动态热加载到所有已有连接,新连接才生效。
为什么 PROCESSLIST 里看不到阻塞源?
常见误区:查 SHOW PROCESSLIST; 发现没有 State 是 Locked 或 Waiting for table metadata lock 的线程,就以为没阻塞。其实 InnoDB 行锁不体现在 PROCESSLIST 的 State 字段里——它只反映连接层状态,不是引擎层锁状态。
真正有效的做法是交叉验证:
- 从
INNODB_TRX拿到trx_mysql_thread_id - 去
INFORMATION_SCHEMA.PROCESSLIST查对应ID,看Command是Sleep、Query还是Connect,再看Time是否远大于正常值(比如 > 60s) - 如果
State = Sleep且Time很大,而INNODB_TRX.trx_state = RUNNING,那八成是代码里BEGIN了没COMMIT或ROLLBACK
复杂点在于:阻塞源可能早已执行完 SQL,但事务没关;也可能在做 HTTP 调用或文件 IO,MySQL 层面只看到它“活着”,却不知道它卡在哪。这时候必须结合应用日志反查线程 ID 对应的业务路径。

















