记一次mysql锁阻塞问题

141 阅读1分钟

1、事故现象 在一段事务内,执行到一个更新sql会阻塞(100%重现),导致接口超时/数据错误 sql:UPDATE user set money = money + 100 where user_id = 1

2、分析原因: 通过以下事务相关参数配置和日志分析

SHOW ENGINE INNODB STATUS ; // 它打印了很多关于 InnoDB 内部性能相关的计数器、统计、事务处理信息等,不过它显示的不是当前状态,而是过去某个时间范围内InnoDB存储引擎的状态

show FULL processlist; // 它可以查看当前 mysql 的一些运行情况,是否有压力,都在执行什么 sql,语句耗时几何,有没有慢 sql 在执行等等

SELECT * FROM information_schema.INNODB_TRX; SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

通过查询结果能看到sql阻塞时,有两个事务正在执行,一个持有S锁,一个等待获取X锁,所以阻塞的原因就是行级的X锁被S锁阻塞了(跟隔离级别有关),具体哪个地方触发的S锁未知

网上找到一个跟此次事故类似的mysql官方的的bug文档 文档地址: bugs.mysql.com/bug.php?id=… 大概原因就是: 死锁检测机制导致的误判

3、解决方式 update语句使用表连接的形式,避免行级锁升级为表级锁 UPDATE user t LEFT JOIN user p ON t.user_id = p.user_id SET t.money = (p.money+100) where t.user_id = 1