【MySQL】数据库死锁问题排查定位

一、产生死锁的条件

如果我们的数据库并发请求不高一般不会产生死锁。即便存在高并发,也不一定会产生死锁。只有满足一定的条件才会产生死锁,即死锁产生的4个必要条件:

  • 资源排它性。一个资源(数据)只能被一个事务占有;
  • 不可剥夺性。一个事务在占有一份资源期间,该资源不能再被其它事务剥夺;
  • 请求与保持。一个事务在占有一份资源的同时,继续保持请求其它的资源;
  • 循环等待。多个事务在保持占有自己的资源,同时请求其他资源构成了一个环;

二、排查数据库死锁

  1. 首先,确定所使用的数据库的版本:
select version()

在这里插入图片描述
2. 确定数据表使用的存储引擎及表结构信息,以我本地一个数据表为例:

show create table `students`;

在这里插入图片描述
3. 确定当前数据库中事务的隔离级别:

# mysql 8.x 版本
select @@transaction_isolation;
# mysql 5.x 版本
select @@tx_isolation;

在这里插入图片描述
4. 查看死锁日志。同时,我们应该明确一点:数据库表中对字段进行加锁,锁的是索引,所以下面我们下面在查看死锁日志时应该留意加了索引的字段。

  • MySQL5.6及之前的版本可以通过 show engine innodb status 命令来查看最近发生的死锁的死锁日志。可以看到那几个SQL执行形成了死锁,以及他们分别持有哪个锁,在等待哪个锁等;
  • MySQL5.6以上的版本可以通过参数 innodb_print_all_deadlocks 对MySQL进行配置,决定着MySQL 是否开启死锁日志;
# 查询MySQL死锁日志开关是否开启
show variables like 'innodb_print_all_deadlocks';
# 开启MySQL死锁日志
set global innodb_print_all_deadlocks=1;

在这里插入图片描述

如果开启了死锁日志,死锁日志就会被输出到MySQL的错误日志中,通过 show variables like 'log_error%' 查看MySQL错误日志的路径,在对应的错误日志路径下查看对应的文件内容。

在这里插入图片描述

三、死锁解决办法

3.1 一个事务中多个SQL访问多张表产生死锁

  • 看是否可以指定获取表上记录的顺序。例如将业务上使用的所有表都设置一个序号,当在一个事务中执行多个SQL ,要获取到多个锁时,我们按照表序号的顺序获取锁,如果可以获得所有的锁则提交该事务,否则立刻回滚。
  • 当然,要尽量避免长事务,不推荐在一个事务里执行多个SQL。

3.2 重新定义索引

  • 需明确:数据库上的锁是加在索引上的。所以,当索引的区分度不够的时候,一个索引值可能会对应很多的数据,这也意味着如果一个事务对一条索引值加了锁,这个索引值对应记录的请求事务都可能被锁住。这很大程度提高了死锁发生的概率。

3.3 降低事务隔离级别

  • 如果数据库并发度较高的话,可通过降低事务的隔离级别进一步提高并发。MySQL的默认隔离级别是 Repeatable Read,如果业务场景上较少发生幻读或者对幻读容忍度高,可将事务的隔离级别调整到Read Committed
  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值