本文共 1784 字,大约阅读时间需要 5 分钟。
近期项目中,数据库查询频繁出现挂起现象,应用程序启动后也经常报操作超时。测试人员反馈数据库连接失败,所有查询都无法完成,通过使用show processlist
工具查看进程状态,发现屏幕上密密麻麻地充斥着Waiting for table metadata lock
状态的连接。这让我立刻联想到可能存在大量未处理的事务,导致数据库锁机制陷入僵局。
经过初步排查,发现该问题的根源与MySQL的DDL
操作相关。具体来说,当数据库执行alter table
等DDL
操作时,如果涉及的表中存在未提交的事务(UNCOMMITTED TRANSACTIONS
),就会导致Waiting for table metadata lock
状态出现。一旦进入此状态,后续对该表的所有操作都会被阻塞,这严重影响了数据库的正常运行。
为了迅速解决此问题,我采取以下步骤进行排查和修复:
首先,需要确认数据库中是否存在未提交的事务。可以通过检查information_schema.innodb_trx
表来获取相关信息。执行以下SQL语句:
SELECT trx_state, trx_started, trx_mysql_thread_id, trx_queryFROM information_schema.innodb_trx\G
trx_state
:表示事务的状态,通常为RUNNING
。trx_started
:记录事务的启动时间,若时间过长,需分析该事务是否合理。trx_mysql_thread_id
:MySQL线程ID,可以用于杀死进程。trx_query
:事务中执行的具体SQL语句。通过查看这些信息,可以快速定位到可能导致问题的具体事务进程。
默认情况下,lock_wait_timeout
的值为一年(31536000秒),这会导致在出现Waiting for table metadata lock
状态时,数据库等待时间过长,难以及时发现问题。建议将其调整为较短的值,以实现快速故障定位。操作步骤如下:
set session lock_wait_timeout = 1800; # 30分钟set global lock_wait_timeout = 1800;
这样一来,当出现Waiting for table metadata lock
状态时,数据库会在30分钟后自动终止相关进程,从而避免长时间阻塞。
如果通过调整锁超时阈值仍未解决问题,下一步就是直接清理现有的阻塞进程。可以通过以下命令快速定位并杀死相关进程:
#!/bin/bashmysql -u root -e "show processlist" | grep -i "Locked" > locked_log.txtfor line in `cat locked_log.txt | awk '{print $1}'` do echo "kill $line;" done
生成的kill_thread_id.sql
文件将包含所有需要杀死的线程ID,执行该脚本即可清除所有阻塞进程:
kill 66402982;kill 66402983;kill 66402986;kill 66402991;...
当然,也可以通过以下命令一行完成:
for id in `mysqladmin processlist | grep -i locked | awk '{print $1}'` do mysqladmin kill $iddone
Metadata Lock
阻塞。Metadata Lock
的依赖,避免长时间持有锁的情况。本文最初发布于51CTO博客。如需进一步了解相关技术,建议访问该链接查看完整内容。