mysql 通过不同索引更新相同记录会导致死锁吗

背景

假设有一张用户表。其中id是主键列,cn_name+is_deleted上面有二级索引cn_del_index, en_name+is_deleted上面有二级索引en_del_index.

create table user(
id bigint(20) not null primary key comment '主键',
cn_name varchar(100) not null comment '中文名称',
en_name varchar(100) not null comment '英文名称',
is_deleted int not null comment '是否删除'index cn_del_index('cn_name','is_deleted'),
index en_del_name('en_name','is_deleted')
)engine = innodb;
insert into user value(1, 'lixia', 'jame', 0); 
...模拟插入很多条记录

应用程序并发执行如下两条语句:

update user set is_deleted=1 where cn_name='lixia'
update user set is_deleted=1 where cn_name='jame'

问题:这种情况下数据库会产生死锁吗?

回答1: 最坏情况下只会产生锁等待超时,不会死锁,原因是两条sql语句之间由于更新同一条记录,只需要等待另一个语句执行完即可,不会循环依赖资源,所以不会产生死锁

回答2: 并发情况下有产生死锁的可能性。

那么哪个回答是正确的呢?

技术知识

mysql数据加锁原理

对于mysql而言,我们这里只是拿innodb存储引擎举例,
一. 当执行update user set is_deleted=1 where cn_name='lixia' 这样一行update语句时,它首先需要获取以下的锁,第一个是二级索引cn_del_index上面的锁,第二个是获取主键的锁id=1,这样他就找到了对应要锁的记录了,注意这里只是第一阶段要获取的锁,由于把找到的记录的is_deleted字段更新成1后,为了保持二级索引和数据记录的数据一致性,还需要获取使用了is_deleted字段的其他二级索引的锁,比如这个例子中的en_del_index的锁(对应主键id=1).

二. 当执行update user set is_deleted=1 where cn_name='jame' 这样一行update语句时,它首先需要获取以下的锁,第一个是二级索引en_del_index上面的锁,第二个是获取主键的锁id=1,这样他就找到了对应要锁的记录了,注意这里只是第一阶段要获取的锁,由于把找到的记录的is_deleted字段更新成1后,为了保持二级索引和数据记录的数据一致性,还需要获取使用了is_deleted字段的其他二级索引的锁,比如这个例子中的cn_del_index的锁(对应主键id=1).

总结

到这里我们问题的答案已经和明显了,前面这两条sql更新记录的时候获取锁的完全可能形成互相等待的局面,比如如下:
1.第一个sql先获取了cn_del_index上面的锁,随后获取了id=1的主键上的锁,即将想要获取en_del_index上面的锁
2.第二个sql获取了en_del_index上面的锁,即将想要获取id=1主键上的锁
这种情况下两个sql互相等待对方持有的锁,死锁条件形成。

如何解决

首先我们需要意识到对于mysql最常用的read_commit隔离级别下,即使我们没有主动使用begin/end transaction开启事务,单sql语句本身也可能会导致死锁,所以应用程序需要意识到可能会产生这种死锁异常,产生死锁之后最常见的处理就是简单的重试即可.
其次,我们可以尽量减少要锁定的记录数量(比如分批执行)
来减少死锁发生的概率。
最后,我们可以限定在每次更新记录时都使用相同的二级索引,这样加锁顺序一样自然就没有死锁的问题了,最多只可能是锁等待超时

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中提到MySQL有三种的级别:页级、表级、行级。其中表级是一种常见的定方式,它的加快、开销小,但定粒度大,可能导致冲突和并发度较低。当在MySQL中添加索引时,如果表的数据量很大,就有可能导致表被,即其他操作需要等待索引添加完成才能继续执行,从而造成查询超时和的问题。 引用建议,在一张数据量很大的表上添加索引时,应该谨慎操作,尽量避免轻易添加索引。如果非要添加索引,最好先备份数据表,然后对空表进行添加索引的操作,这样可以减少对表的定时间和影响。 另外,如果在添加索引的过程中发现表被,可以通过查看执行语句的线程状态和ID,然后使用kill命令终止该线程,从而释放对表的定,解决问题。所以,MySQL在添加索引时有可能表,特别是在数据量很大的情况下,因此在进行索引优化时需要注意的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [MySQL添加索引导致问题](https://blog.csdn.net/weixin_42324471/article/details/123899776)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [mysql添加索引导致](https://blog.csdn.net/u014466635/article/details/119680075)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值