数据库死锁引发的掉单问题排查

本文通过实例解析MySQL中因类型转换导致的死锁问题。详细分析了唯一索引失效的原因及如何通过正确设置数据类型避免全表扫描,进而解决死锁。提供了show engine innodb status和explain等命令的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

建议手动复现一下,和只看是两码事、、、、、、、、、、、

1、问题描述

           场景:订单支付成功后用订单号批量通知修改计息状态发生死锁

2、前提:数据库表订单号varchar类型唯一索引跟图中name字段相同

3、操作流程

update book set platform_version=400 where name=1111

由于修改订单为批量操作,并且为一条一条修改库表

4、分析:name为唯一索引应该锁行修改,为什么会发生死锁,猜想肯定是两个事物相互依赖导致

分析一show engine innodb status;命令

 

第一部分,关键词是:

(1)Transaction 1,事务105528;

(2)在执行update book set platform_version=400 where name=2222

(3)正在等待锁释放(waiting for this lock to be granted),记录锁(record locks),主键索引上(index primary),互斥锁(lock_mode X),物理记录(physical record),asc 3333;

分析完这个最近一次死锁后还是有疑问:2222唯一索引干嘛还要拿3333的锁,闹腾、、、、、

分析二explain小工具查看执行计划

select_type:UPDATE

这是一个简单类型的SQL语句,不含子查询或者UNION。

type:index

访问类型,即找到所需数据使用的遍历方式,潜在的方式有:

(1)ALL(Full Table Scan):全表扫描;

(2)index:走索引的全表扫描;

(3)range:命中where子句的范围索引扫描;

(4)ref/eq_ref:非唯一索引/唯一索引单值扫描;

(5)const/system:常量扫描;

(6)NULL:不用访问表;

这里为什么是index,唯一索引不应该是走单条吗,怎么会扫全表

key: PRIMARY

实际使用索引:这个是走的主键索引

ref:NULL

哪些列,或者常量用于查找索引上的值,我们条件name说明索引没好使、、、、

rows:7

找到这条数据预读了7行,,尴尬,这不正是全表吗

到这里很明显我们的name唯一索引并 没有起作用,为什么、、、、、

 

这个时候回到表结构name 是varchar类型,而sql

update boot set platform_version=400 where name=3333;

name用的number类型,,,

类型转换,导致锁升级,造成全表扫、、、

重新执行sql:

果然印证了猜想:

(1)type:range,变为了走索引的字符串比对,范围扫描;

(2)possible_keys:index_name,通过index_name索引找到了记录;

(3)key:index_name,实际使用index_name索引;

(4)ref:const,使用了常量' 3333'进行比对;

(5)rows:1,预估读取行数是1;

 

就本例而言:需要注意字符串与整数之间的强制类型转换,有时候少一个引号,就会使得行锁升级为表锁。

 

死锁是MySQL中非常难调试的问题,常见的思路与方法有:

(1)通过多终端模拟并发事务,复现死锁;

(2)通过show engine innodb status; 可以查看事务与锁的信息;

(3)通过explain可以查看执行计划

公众号主要记录各种源码、面试题、微服务技术栈,帮忙关注一波,非常感谢

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值