1.前言
今天线上环境日志,突然出现一个错误:Lock wait timeout exceeded; try restarting transaction)。凭经验可以推断,这是有某个事务直接时间太长没有提交,导致其他事务等待超时了。那么具体怎么排查呢?
今天我在做一个关于事务的小测试。
表结构:
CREATE TABLE `test` (
`id` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test` VALUES ('1', '1');
INSERT INTO `test` VALUES ('2', '1');
然后我在一个窗口中执行:
第一个窗口:
BEGIN;
UPDATE test SET age =2 where id =1;
第二个窗口:
BEGIN;
UPDATE test SET age =3 where id =1;
COMMIT;
然后先执行第一个窗口,再执行第二个窗口
看到第二个窗口会一直阻塞等待,最后抛出异常:
Lock wait timeout exceeded; try restarting transaction
2.原因探查
我们可以通过到information_schema 中来进行查找。
innodb_trx
当前运行的所有事务innodb_locks
当前出现的锁innodb_lock_waits
锁等待的对应关系
所以我们先查看
select * from information_schema.innodb_trx;
结果如下:
看到当前有两个事务,一个运行中,一个LOCK WAIT,锁等待,即等待获取锁。从这里,我们看到事务的id、事务开始时间、事务的线程id;
然后我们再执行下面的语句:
select * from information_schema.innodb_locks ;
结果如下:
最后我们再执行下面的语句:
select * from information_schema.innodb_lock_waits ;
结果如下:
所以,如果我们看到一个事务执行时间太长,我们可以杀掉这个事务,
怎么杀掉事务:
比如这个,我们看到trx_id=4F3E的事务一直运行中,执行时间比较长,所以可以把它kill掉。这个事务的线程id=839,
所以我们直接执行:
kill 839
然后我们看到第一个第二个窗口停止等待,事务提交。