mysql的一则事务锁的问题Lock wait timeout exceeded.m

时间:2022-06-26
本文章向大家介绍mysql的一则事务锁的问题Lock wait timeout exceeded.m,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

今天在测试环境上发现用户第三方登录出现问题,服务器日志报错如下:

出现这个问题感觉还是挺疑惑的,因为测试环境已经稳定运行了几个月的时间,一直没有出现过mysql事务锁的问题,于是开始着手查问题。

1. 问题分析

针对Lock wait timeout exceeded; try restarting transaction的错误出现的原因一般有:

  • 在同一个事务内先后对库中同一条记录进行事务操作,如更新、删除等;
  • 并发操作库中同一条记录,出现锁竞争,一个线程获取锁后迟迟不释放,导致另一个尝试获取锁的线程超时。
  • 在innoDB引擎下,默认的innodblockwait_timeout参数设置锁等待的时间是50s,一旦数据库锁超过这个时间就会报错。

2. 查找问题

先从mysql角度来对问题进行分析,查看mysql server上的事务情况和锁的情况以及锁等待的情况。

2.1. 查看进程

SHOW PROCESSLIST;

输出结果为:

2.2. 查看事务情况

select * from informationschema.innodbtrx

其中字段说明如下(这里只简要列举关键的几个字段,需要了解更多的请自行到官网查询):

  • trx_state:事务状态
  • trx_start:事务开始时间
  • trxrequestedlockid:innodblocks.lock_id
  • trxwaitstarted:事务开始等待的时间
  • trxmysqlthread_id:事务线程id
  • trxtableslocked:事务拥有多少个锁
  • trxisolationlevel:事务隔离级别

在我们的环境中执行后,结果为:

对比可以看到,记录的状态都为RUNNING,也就是正在执行的事务,并没有锁。

如果是事务锁定的情况如何解决?看事务表INNODB_TRX,里面是否有正在锁定的事务线程,看看ID是否在show processlist里面的sleep线程中,如果是,就证明这个sleep的线程事务一直没有commit或者rollback而是卡住了,我们需要手动kill掉。

2.3. 查看锁情况

SELECT * FROM informationschema.INNODBLOCKs;

可以看到锁也是没有的。

2.4. 查看锁等待情况

SELECT * FROM informationschema.INNODBLOCK_waits;

当前环境中也并无锁等待情况,这时就开始往其他方面分析了。

2.5. 查看mysql日志情况

由于当前测试环境是一个mysql的主从环境,所以会有很多的binlog日志,所以猜测是不是因为binlog空间占用太多的原因。进入mysql存储目录后发现:

可以看到binlog日志文件应该是已经及时被定时清理了,但是mysqld.log和slow.log都比较大,查看mysqld.log,会发现有大量的:

经过定位,发现这个是一个同事最近在调整的统计信息的定时任务,不小心把定时任务的频率调大了,导致频繁刷mysqld.log,定时任务频率恢复正常后,log日志不再增长。slow.log也是因为统计信息中的一些sql的问题导致的。

清空这两个文件:

echo > mysqld.logecho > slow.log

清空成功后,再尝试登录时,成功了。

虽然这里不是binlog的问题,但是还是有必要在这里安利下binlog的管理方法:

  • 登录mysql:mysql -u root -p
  • show binary logs; show variables like '%log%';show master logs;查看多少binlog日志,占用多少空间。
  • 手动清理1:PURGE MASTER LOGS TO 'mysql-bin.002467'; 删除mysql-bin.002467以前所有binlog,这样删除可以保证*.index信息与binlog文件同步。
  • 手动清理2:PURGE MASTER LOGS BEFORE DATESUB(CURRENTDATE, INTERVAL 10 DAY); 手动删除10天前的binlog日志。
  • 设置自动清理:set global expirelogsdays = 5; 把binlog的过期时间设置为5天; mysql> flush logs; 刷新log使上面的设置生效。为保证在MYSQL重启后仍然有效,在my.cnf中也加入此参数设置expirelogsdays = 5。

更多可以参考:https://blog.csdn.net/atco/article/details/24259333

3. 总结

出现Lock wait timeout exceeded; try restarting transaction的原因一般为:

  • 多线程并发更新时,一个线程事务操作比较耗时,导致其他线程获取锁超时,这个需要查看代码问题并且要kill掉mysql中锁死的线程。
  • binlog日志文件过大,空间不足,清理binlog文件。
  • 其他mysql日志文件过大,清理日志文件。
  • 其他原因。