为什么mysql insert会导致锁等待超时异常

时间:2016-06-19 12:51:43

标签: mysql transactions mybatis

执行单元测试(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 document我知道

  

InnoDB事务在放弃之前等待行锁定的时间长度(以秒为单位)。默认值为50秒。尝试访问由另一个InnoDB事务锁定的行的事务在发出以下错误之前最多等待这一行以便对该行进行写访问:

     
    

ERROR 1205(HY000):超出锁定等待超时;尝试重新启动交易

  

所以我认为只有当更新某些行可能有这个异常,但我的insert操作时,为什么还有这个异常?我怎么能直接在mysql会话中重现它?

2 个答案:

答案 0 :(得分:1)

无论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 :(得分:-1)

我认为这个错误是由你的ORM引起的。它将 get_lock 命令发送给mysql。似乎无需为插入记录发送该命令。