记一次mysql锁超时问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hfismyangel/article/details/81908880

当时的业务场景是要为从腾讯云队列拉取的数据做路由,分发到4个环境里(dev/test/preonline/online),先根据环境从不同的db里查询一条记录,如果记录满足条件则通过rest接口调用不同环境的接口修改该条记录。

排查过程:

select * from information_schema.INNODB_LOCK_WAITS
select * from information_schema.INNODB_TRX
show engine innodb status
show variables like 'autocommit'
show PROCESSLIST

查询LOCK_WAITS表发现有一条未提交的事务,查询为空,下面还有一条处于LOCK_WAIT状态的事务,可以看到是UPDATE。

之所以出现锁等待超时的原因是mysql不会为select语句加锁,但执行这段sql的代码被aop的全局事务覆盖了,并设置为了只读事务,这时mysql会为select加上偏向共享锁(IS锁,也称读锁),即允许多个事务同时加S锁/IS锁而不能加X锁,而update、delete、insert语句mysql会为其加上排他锁(X锁,sql后加上for update),加上X锁的事务无法加上任何其它锁,除非释放当前X锁,由于执行select的代码里没有执行完(在等待update的执行结果)不会自动提交,导致共享锁不会释放,而update的排他锁又加不上,在等待select的事务释放共享锁,从而产生死锁。解决方法很简单,将执行select的代码从事务中摘出来,不加事务直接执行即可,当然也是有条件的,insert这条记录的时间和select该记录的时间间隔在5s以上,基本可以确保不会产生脏读问题。

排查的时候特意看了一眼autocommit,是因为之前踩过这个坑,mysql的autocommit被关闭了,导致那一段时间脏读锁行锁表的情况发生很频繁,但万万没想到是autocommit被关了,导致事务执行着就被挂起来。

MySQL InnoDB 锁兼容阵列

  X IX S IS
X
IX
S
IS

猜你喜欢

转载自blog.csdn.net/hfismyangel/article/details/81908880