并发测试的时候遇到Lock wait timeout 和Dead

2021-08-12  本文已影响0人  东南枝下

并发测试时,两个用户并发调用接口,会稳定触发Lock wait timeout

Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
### The error may exist in com/jenson/infra/mapper/Mapper.java (best guess)
### The error may involve com.jenson.infra.mapper.Mapper.delete-Inline
### The error occurred while setting parameters
### SQL: DELETE FROM line WHERE header_id = ? AND tenant_id = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction\n; Lock wait timeout exceeded; try restarting transaction;
...

分析:该接口是先删除一批指定header_id的行数据,再创建一批该header_id的行,在执行到第一步删除数据时,遇到锁等待超时。

参考资料知道,mysql的行锁是通过索引加载的,即行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,行锁则无法实现,取而代之的是表锁。

所以给表增加索引 line_n1(header_id,tenant_id)

问题解决

但在执行到第二步并发批量插入行数据时发生了死锁。

报错如下:


图片.png

查看死锁日志 show engine innodb status , 如下

图片.png

发现确实是在两个事务并发插入数据时发生的死锁

分析:
因为mysql的默认数据隔离级别是“可重复读”(select @@tx_isolation;可查询)
在可重复读的隔离级别下,为防止幻读的产生,使用了间隙锁,估计就是这个间隙锁导致的死锁。

解决方式:
由于当前的业务场景并不会产生幻读,将事务隔离级别改为“读已提交”

@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)

ps:
幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
即:一个事务读取到了另一个事务中提交的 insert 的数据。


参考博文:https://www.cnblogs.com/zjfjava/p/11002147.html
参考博文:https://www.lixueduan.com/post/mysql/04-cap-lock/#3-%E9%97%B4%E9%9A%99%E9%94%81gap-lock

上一篇下一篇

猜你喜欢

热点阅读