如何解决Mysql报错Deadlock found when trying to get lock;try restarting transaction问题

 更新时间:2024年05月29日 11:32:24   作者:从百草园杀到三味书屋&  
这篇文章主要介绍了如何解决Mysql报错Deadlock found when trying to get lock;try restarting transaction问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

问题发生场景

记录一下最近项目中遇到的一个问题,前几天在部署项目后,在线上运行过程中,突然报了入下这样的错误,从报错信息中我们可以看到,是mysql在执行update操作的时候报了一个死锁的问题,今天解决了,特此记录一下。

Mysql锁类型分析

MySQL有三种锁的级别:页级、表级、行级,这个地方我遇到的问题是来自于行级锁,所以重点说一下。

类型特性
表级锁 (table-level locking)开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁 (row-level locking)开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁 (page-level locking)开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

行级锁在使用的时候并不是直接锁掉这行记录,而是锁索引

  • 如果一条sql用到了主键索引(mysql主键自带索引),mysql会锁住主键索引;
  • 如果一条sql操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引.

死锁原理

mysql的两种锁排它锁(X锁)和共享锁(S锁)(mysql还有其他锁,需要了解可以自己去查,这个地方列举两个):

  • X锁,是事务T对数据A加上X锁时,只允许事务T读取和修改数据A,别的事务就没办法读取和修改,所以也叫排它锁,是互斥的
  • S锁,是事务T对数据A加上S锁时,其他事务只能再对数据A加S锁,而不能加X锁,直到T释放A上的S锁,别的事务也用加S锁,所以也叫共享锁,是不互斥的

一般造成死锁的原因是因为两个事物添加锁的时候没能及时的解锁释放资源,等到第二个事务要添加锁的时候发现已经被锁,从而造成环路等待,构成死锁条件。

问题排查过程

通过上面log日志中的报错信息,能很快确认报错的准确位置

这个地方是执行了一个update的操作,我找到了了这个表,看了一下这个表的索引是有三个,两个非主键索引,一个主键索引.

果然,在图中这两条索引在那个update语句中都有进行的操作,具体如下:

然后我又找了一下有可能会跟这条语句发生冲突的地方,果然在这个报错信息的上面,执行了一条这样的sql,这两条sql执行的间隔仅仅不超过1毫秒

根据上面所说的,如果一条sql用到了主键索引(mysql主键自带索引),mysql会锁住主键索引;

如果一条sql操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引.

因此sql(2)在使用的时候用到了schedu_id这个非主键索引,还需要锁定主键索引,然而此时sql(1)开始执行

然后锁定了主键索引,但是在set操作中还用到了schedu_id这个非主键索引,但是这个索引在sql(1)执行的时候还在处于被锁的状态,因此两条sql就出现了对索引资源的竞争,造成了死锁.

问题原因

我的事务1中update wc_examine会多很多个update,这里有N行记录被锁定,事务的更新大量数据时间比较长,更新会加x锁,而此时事务2是UPDATE wc_examine ,在update之前先执行了select 操作,添加了S锁,然后想要update的时候添加X锁。

事务1的X锁正准备加上还是还没加上,实际是存在X锁,但是事务2加了s锁,事务1会等待事务2的s锁 事务2的完整事务加了s锁立即就要加x锁,但是事务1的x锁没有释放。造成了环路等待。

解决方法

这个地方,代码的问题需要根据情况自己去修改,可以试着把索引去掉(有风险),或者在进行update的时候尽量避开非主键索引,我这里记录一下被锁后应该怎么去解决的方法,首先先用sql查询一下mysql的事务处理表

select * from information_schema.INNODB_TRX  

正常情况下的状态都是RUNNING,但是在被锁之后就会变成LOCK WAIT ,一旦出现这种情况,就得杀死这个进程,如果进程杀不死就只能重启Mysql服务了

杀死进程

kill 进程ID

然后系统就能继续运行了

经验教训

无论前台后台的程序,都不应该存在仅根据非主键的几个字段一查就要update/delete的场景。

即使有,也应该改为先把要更新的记录查出来然后逐条按主键id更新。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 解决MySQL安装重装时出现could not start the service mysql error:0问题的方法

    解决MySQL安装重装时出现could not start the service mysql error:0问题的方法

    这篇文章主要为大家详细介绍了解决MySQL安装重装时出现could not start the service mysql error:0问题的方法,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • MySQL使用外键实现级联删除与更新的方法

    MySQL使用外键实现级联删除与更新的方法

    这篇文章主要介绍了MySQL使用外键实现级联删除与更新的方法,详细分析了mysql数据库与表的创建、数据插入、查询以及外链的使用与级联操作相关技巧,需要的朋友可以参考下
    2016-07-07
  • MySql 字符串中提取数字的实现示例

    MySql 字符串中提取数字的实现示例

    在MySQL中,有时需要从字符串中提取数字,本文就来介绍一下MySql 字符串中提取数字的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • 浅谈MySQL和Lucene索引的对比分析

    浅谈MySQL和Lucene索引的对比分析

    下面小编就为大家带来一篇MySQL和Lucene索引的对比分析。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • 如何区分MySQL的innodb_flush_log_at_trx_commit和sync_binlog

    如何区分MySQL的innodb_flush_log_at_trx_commit和sync_binlog

    这篇文章主要介绍了如何区分MySQL的innodb_flush_log_at_trx_commit和sync_binlog,帮助大家更好的理解和使用MySQL数据库,感兴趣的朋友可以了解下
    2021-02-02
  • MySQL 强制使用特定索引的操作

    MySQL 强制使用特定索引的操作

    MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异,建议优化索引结构而非强制使用,本文介绍MySQL 强制使用特定索引的操作,感兴趣的朋友一起看看吧
    2025-07-07
  • 如何优雅、安全的关闭MySQL进程

    如何优雅、安全的关闭MySQL进程

    这篇文章主要介绍了如何优雅、安全的关闭MySQL进程,帮助大家更好的理解和学习MySQL,感兴趣的朋友可以了解下
    2020-08-08
  • mysql数据校验过程中的字符集问题处理

    mysql数据校验过程中的字符集问题处理

    在日常应用中,我们经常会遇到在不同的字符集的数据库直接进行数据的导入导出操作,针对这个问题,我们来进行讨论下
    2014-05-05
  • MySQL数据库迁移实战

    MySQL数据库迁移实战

    数据库迁移是指将一个数据库从一种系统转移到另一种系统或从一台服务器迁移到另一台服务器的过程,本文主要介绍了MySQL数据库迁移实战,感兴趣的可以了解一下
    2023-11-11
  • 银河麒麟V10 x86安装MySQL 8.0超详细步骤记录

    银河麒麟V10 x86安装MySQL 8.0超详细步骤记录

    MySQL广泛用于Web应用程序的后端数据库存储,因为它是一个快速、稳定、可靠且易于使用的数据库系统,下面这篇文章主要介绍了银河麒麟V10 x86安装MySQL 8.0超详细步骤的相关资料,需要的朋友可以参考下
    2026-04-04

最新评论