为什么MySQL插入可能会导致锁等待超时异常。

3

当执行单元测试(mvn test)时,有时会出现以下异常:

org.springframework.dao.CannotAcquireLockException:

### Error updating database.  Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
### The error may involve com.foo.dao.mapper.TestMapper.insertSuccesfulPaymentOrder-Inline
### The error occurred while setting parameters
### SQL: insert into order(order_seq,note,user_id,product_id, pay_status) values(uuid(),'',?,?,1)
### Cause: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
; SQL []; Lock wait timeout exceeded; try restarting transaction; nested exception is java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction

mysql文档中,我了解到:

InnoDB事务在放弃之前等待行锁的时间长度(以秒为单位)。默认值为50秒。如果一个事务尝试访问被另一个InnoDB事务锁定的行,则在发出以下错误之前,最多等待此多秒钟以获得对该行的写入访问权限:

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

因此,我认为只有在更新某些行时才会出现此异常,但我的操作是插入,为什么仍然会出现此异常?如何在mysql会话中直接重现它?


运行 SHOW ENGINE INNODB STATUS; 命令以查看发生了什么。 - Bernd Buffen
嗨 @BerndBuffen,我无法提供给您,因为我现在执行的是 mvn test,它是正常的。可惜我不知道什么时候会再次发生。所以我想知道如何直接在 MySQL 控制台中重现它。 - zhuguowei
如果没有更新的锁定信息,那么旧的锁定信息将显示在状态中。 - Bernd Buffen
2个回答

6
无论ORM使用get_lock()的情况如何,50秒的默认值可能意味着有另一个长时间运行的查询,这可能是不希望出现的多种原因之一。如果在开发数据库实例上的单元测试中遇到锁等待超时,则特别如此。

因此,您需要使问题可重现,并确定哪个查询(而不是插入)有罪并具有锁定。

增加默认超时时间以在mysql cli上提供足够的交互时间。运行测试并在获得锁等待超时的测试上打断点。
SELECT * FROM `information_schema`.`innodb_locks`;

将显示当前的锁定情况。

select * from information_schema.innodb_trx where trx_id = [lock_trx_id];

将显示涉及到的交易。
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST where id = [trx_mysql_thread_id];

将显示涉及的连接并可能显示导致锁等待超时的查询。 可能存在未提交的事务。


-1
我认为这个错误是由你的ORM引起的。它向MySQL发送了get_lock命令。似乎在插入记录时不需要发送该命令。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接