一次代码报错的分析:MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

1. 报错信息

### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
; SQL []; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

2. 报错原因

  1. 两个事物之间出现死锁,导致另外一个事物超时
  2. 某一种表频繁被锁表,导致其他事物无法拿到锁,导致事物超时

3. 问题过程

  1. 查看数据库当前的进程,看一下有无正在执行的慢SQL记录线程。
mysql> show  processlist;
  1. 查看当前的事务
当前运行的所有事务:
mysql> SELECT * FROM information_schema.INNODB_TRX;
当前出现的锁
mysql> SELECT * FROM information_schema.INNODB_LOCKs;
锁等待的对应关系
mysql> SELECT * FROM information_schema.INNODB_LOCK_waits;
  1. 解释:看事务表INNODB_TRX,里面是否有正在锁定的事务线程,看看ID是否在show processlist里面的sleep线程中,如果是,就证明这个sleep的线程事务一直没有commit或者rollback而是卡住了,我们需要手动kill掉。
    搜索的结果是在事务表发现了很多任务,这时候最好都kill掉。

  2. 批量删除事务表中的事务
    我这里用的方法是:通过information_schema.processlist表中的连接信息生成需要处理掉的MySQL连接的语句临时文件,然后执行临时文件中生成的指令。

mysql>  select concat('KILL ',id,';') from information_schema.processlist where user='cms_bokong';
+------------------------+
| concat('KILL ',id,';') |
+------------------------+
| KILL 10508;            |
| KILL 10521;            |
| KILL 10297;            |
+------------------------+
18 rows in set (0.00 sec)

当然结果不可能只有3个,这里我只是举例子。参考链接上是建议导出到一个文本,然后执行文本。而我是直接copy到记事本处理掉 ‘|’,粘贴到命令行执行了。都可以。

kill掉以后再执行SELECT * FROM information_schema.INNODB_TRX; 就是空了。

这时候系统就正常了

故障排查

mysql都是autocommit配置
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)

参考:MySQL事务锁问题-Lock wait timeout exceeded


4. 问题解决

经过了解业务信息,一次性执行500次的UPDATE操作,一次UPDATE耗时100毫秒,导致表被锁50秒。

为被更新操作增加索引之后,此问题解决,执行速度加快。

你可能感兴趣的:(Java,MySQL)