一次数据库死锁的记录Deadlock found when trying to get lock; try restarting transaction

背景

电商平台系统中,在秒级别并发下单时,需要去修改数据库表中的发货状态。这是就会有多个事务去请求修改。

报错信息

Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction


报错.png

分析

从日志来看,修改状态这个oder_sn最终没有持久化到数据库中。说明该记录被回滚了。数据库层面的死锁。
我们发现死锁前的操作是想去修改order表这一条记录的状态,然后就死锁了。
因为这个时候是并发下单的。说明不止一个事务提交进来。可能事务A和事务B都想要去修改自己记录的状态。
如果 order_sn字段上没有索引,数据库为了找到需要更新的那一行,会进行全表扫描
在这个过程中,InnoDB 引擎会锁定所有它扫描过的行,即使这些行最终并不符合 WHERE条件(只是先锁住,再判断)。在高并发环境下,如果多个事务同时执行此更新操作,每个事务都可能锁住大量记录,极易形成循环等待,从而触发死锁
。MySQL 检测到死锁后,会选择回滚其中一个事务,导致看到的 Deadlock found when trying to get lock错误

解决

最方便的解决措施就是给表字段加索引。
也可以优化代码。事务尽可能小且执行速度快

ALTER TABLE static_ip_order ADD INDEX idx_order_sn (order_sn);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。