面试必问:MySQL死锁是什么,如何解决?(史上最全)

MySQL死锁接触少,但面试又经常被问到怎么办?

最近有小伙伴在面试的时候,被问了MySQL死锁,如何解决?
虽然也回答出来了,但是不够全面体系化,

所以,小北给大家做一下系统化、体系化的梳理,帮助大家在面试过程中能够脱颖而出,拿到自己心仪的Offer

插播一条:如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题。

1. 什么是MySQL死锁?

MySQL中的死锁是指两个或多个操作相互等待对方释放资源,结果导致他们都无法继续执行的情况。

可以想象成两个人各自拿着对方需要的东西,却都僵持不下,谁也不愿意先放手。

在数据库操作中,这通常发生在多个事务同时试图锁定对方已锁定的资源时。

2. MySQL锁的分类

MySQL的锁可以从操作的粒度进行分类,主要包括表级锁行级锁页级锁

不同类型的锁在数据库操作中的应用会影响数据库的性能和并发处理能力。

表级锁:

表级锁是最简单的锁类型,当操作涉及到整个表时使用。

这种锁会锁定整个表,使得任何其他需要访问这个表的操作都必须等待锁被释放。

例如:

--手动增加表锁
lock table 表名称 read(write),表名称2 read(write);
--查看表上加过的锁
show open tables;
--删除表锁
unlock tables;

优点是简单易管理,但缺点是并发能力较低,尤其在处理大量事务时,效率会大大降低。

行级锁:

行级锁是最精细的锁,只锁定数据表中的特定行。

行级锁的特点

  • 每次操作锁住一行数据。开销大,加锁慢;
  • 会出现死锁;
  • 锁定粒度最小,发生锁冲突的概率最低,并发度最高。

InnoDB相对于MYISAM的最大不同有两点:

  • InnoDB支持事务(TRANSACTION)
  • InnoDB支持行级锁

注意,InnoDB的行锁实际上是针对索引加的锁(在索引对应的索引项上做标记),不是针对整个行记录加的锁。并且该索引不能失效,否则会从行锁升级为表锁。(RR级别会升级为表锁,RC级别不会升级为表锁)

比如我们在RR级别执行如下sql:

--where条件里的name字段无索引
select * from account where name = 'lilei' for update; 

则其它Session对该表任意一行记录做修改操作都会被阻塞住

页级锁:

页级锁介于表级锁和行级锁之间,不是MySQL默认使用的锁类型。

它锁定数据库页(即一组行),粒度比表级锁细,但比行级锁粗。页

级锁可以减少锁的数量,从而降低锁竞争,但可能会引起更多的锁冲突,尤其是当多个事务频繁修改相邻的数据时。

插播一条:如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题。

3 从操作的类型进行的mysql锁的分类

读锁(S锁):

  • 性能特点:

读锁也被称为共享锁,它允许一个事务去读取一行数据,并防止其他事务对这行数据进行写操作,直到读锁被释放。

但是,多个事务可以同时持有对同一资源的读锁,这意味着多个用户可以同时读取数据,而不会相互影响。

例如:

select * from T where id=1 lock in share mode
  • 适用场景:

适用于那些读取操作远多于写入操作的场景。

因为读锁可以共享,它支持高并发的读取操作,使得多个用户可以同时查询数据而不会阻塞彼此。

写锁(X锁):

  • 性能特点:

写锁又称为排他锁,当一个事务对数据进行修改时,它会加上写锁。这个锁会阻止其他任何事务读取或修改同一数据,直到写锁被释放。

写锁保证了数据在修改期间的完整性和一致性。

例如:

select * from T where id=1 for update
  • 适用场景:

适用于需要修改数据的操作。

由于写锁会阻塞其他所有试图访问相同数据的操作,所以在写入量大或者数据频繁更新的应用中,写锁可能会成为性能瓶颈。

意向锁:

  • 性能特点:

意向锁是一种较为特殊的锁,它不直接锁定数据,而是表明一个事务意图对数据行进行加锁(读锁或写锁)。

意向锁主要分为

  • 意向共享锁,IS锁,对整个表加共享锁之前,需要先获取到意向共享锁。
  • 意向排他锁,IX锁,对整个表加排他锁之前,需要先获取到意向排他锁。

这主要用于支持多级锁定协议,通过在表级别设置意向锁,来预告即将在行级别上加的锁,这样就能在不同粒度的锁之间提供一种兼容性检查。

  • 适用场景:

意向锁主要用于提高并发性能,特别是在存在多粒度锁定(即同时使用表级锁和行级锁)的情况下。

它允许数据库系统更有效地管理锁,避免不必要的锁冲突,提高操作效率。

4 从操作的性能进行的mysql锁的分类

从操作的性能可分为乐观锁和悲观锁

  1. 乐观锁
  • 性能特点:

乐观锁基于这样一个假设,即冲突发生的概率较低,大多数时间不会有冲突。

因此,它在操作过程中不会立即锁定资源。通常,乐观锁会通过检查数据在读取和更新期间是否被修改来实现,常用的方法是使用版本号或时间戳。只有在数据提交更新时,才会检查版本信息是否一致,如果不一致,表示数据在此期间已被其他操作更改,此时操作会失败。

  • 适用场景:

适用于读多写少的场景,比如在线阅读平台的用户数据处理,因为在这种场景中,数据冲突的可能性较低,使用乐观锁可以减少锁的开销,提高系统的整体性能。

  1. 悲观锁
  • 性能特点:

悲观锁恰恰相反,它假设冲突很常见,因此在整个数据处理过程中会保持数据锁定,直到事务完成。

这意味着当一个事务在操作数据时,其他事务必须等待直到锁被释放。悲观锁可以通过数据库自带的锁机制实现,比如行锁或表锁。

  • 适用场景:

适合写操作多的场景,比如银行账户处理,在这种场景下,数据安全和一致性比性能更为重要。悲观锁通过锁定数据来避免数据在多个事务间的冲突,确保数据操作的安全性。

5 InnoDB存储引擎三种行锁模式

当我们谈论InnoDB存储引擎中的行锁模式时,可以把它想象成一种确保数据库中数据安全和准确的机制。这里有三种主要的行锁模式,分别是记录锁、间隙锁和临键锁。

5.1、记录锁(Record Locks):

记录锁是最直接的一种锁。它就像是给数据库中某条具体数据上了一把锁。

这种锁定的目的是为了防止其他用户在事务处理期间修改这条数据。

比如说,如果你正在更新一条记录,系统就会对这条记录加锁,确保没有其他人能够同时修改这条记录,直到你的事务完成。

5.2、间隙锁(Gap Locks):

间隙锁不是锁定单个记录,而是锁定一个范围,但这个范围不包括实际的记录。

想象一下,你想在两条已有记录之间插入一条新记录,间隙锁就会防止其他事务插入到这两条记录之间的空隙里。

Mysql默认级别是repeatable-read,有幻读问题,间隙锁是可以解决幻读问题的。

假设account表里数据如下:

那么间隙就有 id 为 (3,10),(10,20),(20,正无穷) 这三个区间,在Session_1下面执行如下sql:

select * from account where id = 18 for update;

则其他Session没法在这个(10,20)这个间隙范围里插入任何数据。
如果执行下面这条sql:

select * from account where id = 25 for update;

则其他Session没法在这个(20,正无穷)这个间隙范围里插入任何数据。

也就是说,只要在间隙范围内锁了一条不存在的记录会锁住整个间隙范围,不锁边界记录,这样就能防止其它Session在这个间隙范围内插入数据,就解决了可重复读隔离级别的幻读问题。

5.3、临键锁(Next-Key Locks):

临键锁是记录锁和间隙锁的结合体。它同时锁定一条记录和它前面的空隙。

这种锁的作用是,它不仅防止其他用户修改当前的记录,还防止他们在前面的空隙中添加新记录。

这种锁模式是InnoDB用来保持数据完整性和避免幻读(即在一个事务内读取到之前不存在的数据行)的一种方式。

插播一条:如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题。

6 事务隔离级别和锁的关系

6.1 数据库事务的隔离级别

据库事务的隔离级别,目前数据库事务的隔离级别一共有 4 种,由低到高分别为:


事务的四个隔离级别

  • 未提交读(READ UNCOMMITTED)
    所有事务都可以看到其他事务未提交的修改。一般很少使用;
  • 读已提交(READ COMMITTED)
    Oracle默认隔离级别,事务之间只能看到彼此已提交的变更修改;
  • 可重复读(REPEATABLE READ)
    MySQL默认隔离级别,同一事务中的多次查询会看到相同的数据行;可以解决不可重复读,但可能出现幻读;
  • 可串行化(SERIALIZABLE)
    最高的隔离级别,事务串行的执行,前一个事务执行完,后面的事务会执行。读取每条数据都会加锁,会导致大量的超时和锁争用问题;

数据库一般默认的隔离级别为 读已提交 RC ,比如 Oracle,

也有一些数据的默认隔离级别为 可重复读 RR,比如 Mysql。

“可重复读”(Repeatable Read)这个级别确保了对同一字段的多次读取结果是一致的,除非数据是被本身事务自己所修改。

RR它能够防止脏读、不可重复读,但可能会遇到幻读的情况。

6.2 深入探讨事务隔离级别与锁之间的关联

事务隔离级别,源于SQL92标准,为数据库事务的并发控制提供了一种全面解决方案。

它实质上是将锁机制和MVCC(多版本并发控制)技术进行了封装,从而简化了底层实现的复杂性,为用户提供了一个更加友好的接口。

锁,作为数据库实现并发访问控制的核心机制,确保了事务的隔离性。

通过为不同的数据操作施加相应的锁,数据库能够防止多个事务同时读写同一数据,从而维护数据的一致性和完整性。

对于开发者而言,他们通常首先选择一个合适的事务隔离级别。仅当所选的隔离级别无法满足特定的并发需求或解决问题时,才需要考虑在代码中显式地使用锁进行更精细的控制。

值得注意的是,MySQL的默认事务隔离级别是“可重复读”,但根据实际的应用需求,“读已提交”隔离级别也常被推荐,因为它在并发控制和性能之间达到了较好的平衡。

相比之下,Oracle和SQLServer的默认隔离级别则是“读已提交”。

7 死锁产生原因和解决方案

InnoDB与MyISAM的最大不同有两点

  • 支持事务
  • 采用行锁
    行级锁和表级锁本来就有许多不同之处,另外,事务的引入也带来了一些问题 ,比如 死锁

插播一条:如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题。

7.1、表级锁死锁

假设有两个事务,分别在操作两个表:表A和表B。
事务1试图先锁定表A,然后锁定表B。
而事务2试图先锁定表B,然后锁定表A。
用户A和用户B加锁的顺序如下:

  • 用户A–》表1(表锁)–》表2(表锁)
  • 用户B–》表2(表锁)–》表1(表锁)

如果这两个事务同时执行,它们将会相互等待对方释放锁,从而导致死锁。

  • 解决方案

这种死锁比较常见,是由于程序的BUG产生的,除了调整的程序的逻辑没有其它的办法。

  1. 仔细分析程序的逻辑,对于数据库的多表操作时,尽量按照相同的顺序进行处理,
  2. 尽量避免同时锁定两个资源,如操作A和B两张表时,总是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源。

7.2、行级锁死锁

产生原因1

如果在事务中执行了一条没有索引条件的查询,引发全表扫描,行锁 膨胀 为表锁( 或者等价于 表级锁)

多个这样的 锁表事务 执行后,就很容易产生死锁和阻塞,最终应用系统会越来越慢,发生阻塞或 死锁。

  • 解决方案
  1. SQL语句中不要使用太复杂的关联多表的查询;
  2. 使用explain“执行计划"对SQL语句进行分析,对于有全表扫描和全表锁定的SQL语句,建立相应的索引进行优化。
产生原因2

两个事务分别想拿到对方持有的锁,互相等待,于是产生死锁
例如:模拟死锁场景

set tx_isolation='repeatable-read';
Session_1执行:select * from account where id=1 for update;
Session_2执行:select * from account where id=2 for update;
Session_1执行:select * from account where id=2 for update;
Session_2执行:select * from account where id=1 for update;

当出现死锁时,我们可以通过查看近期的死锁日志,来确定死锁的详细信息
例如:

查看近期死锁日志信息:show engine innodb status; 

大多数情况mysql可以自动检测死锁并回滚产生死锁的那个事务,但是有些情况mysql没法自动检测死锁,这种情况我们可以通过日志分析找到对应事务线程id,可以通过kill杀掉

7.3、预防死锁优化实践

1. 维持一致的锁定顺序

确保所有事务都以相同的顺序获取锁。这可以减少锁定冲突的可能性,因为事务不会因为等待其他事务释放锁而相互阻塞。

例如,如果有多个表或资源需要锁定,总是按照相同的顺序(如字典顺序)锁定这些资源。

2. 使用最小的锁粒度

尽量使用行级锁而不是表级锁。

行级锁允许更高的并发,因为它仅锁定需要修改或查询的数据行,而不是整个表。这样,即使多个事务操作同一表,它们也可能操作不同的行,从而减少死锁的风险。

3. 减少事务持续时间

尽量缩短事务的执行时间。

长事务占用锁的时间越长,与其他事务发生冲突的可能性就越大。你可以通过优化查询语句和减少事务中的操作数来减少事务持续时间。

4. 使用锁超时

在某些数据库管理系统中,可以设置锁的超时时间。

这意味着事务在等待锁超过设定的时间后将自动回滚。这不仅可以防止死锁,还可以避免一个事务无限期地等待资源。

5. 死锁检测和回滚

启用数据库的死锁检测功能,让数据库管理系统能够自动检测死锁并回滚某个事务来解锁。

这通常是最后的手段,因为它可能导致数据不一致的问题。应当只在其他方法都无法实现时使用。

6. 避免不必要的锁

审查和优化事务逻辑,确保只锁定必要的资源。

例如,如果事务只读取数据而不进行修改,可以考虑使用非锁定读(例如,在MySQL中使用SELECT … WITH (NOLOCK))。

7. 使用乐观并发控制

在一些场景中,使用乐观并发控制(OCC)而不是悲观锁定可能更合适。OCC通过在事务提交时检查数据是否已被其他事务修改来避免锁定,适用于读多写少的场景。

8. 避免无索引行锁升级为表锁

尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁

9. 监控和日志记录

实施监控和日志记录来跟踪死锁和性能瓶颈。这可以帮助识别导致死锁的具体事务和操作,从而进行针对性的优化。

总结

认真看完本文的小伙伴,看到这里应该对MySQL死锁有一个清晰的认知了,在日常生产环境中,如果遇到死锁了,该怎么办呢?

  • 首先我们想到是要如何解决死锁(通过日志分析,找到它,然后kill掉它)
  • 第二步才是我们要分析死锁产生的原因,尽快优化掉它。

如果认真看到本文的小伙伴,相信对第二步分析死锁,优化死锁都能游刃有余了。

最后说一句(求关注,求赞,别白嫖我)

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。 这是大佬写的, 7701页的BAT大佬写的刷题笔记,让我offer拿到手软

本文,已收录于,我的技术网站 cxykk.com:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享

求一键三连:点赞、分享、收藏

点赞对我真的非常重要!在线求赞,加个关注我会非常感激!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/669893.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Matlab里面的浮点数与FPGA定点数的相互转化应用(含Matlab代码,封装成函数可直接调用)

微信公众号获取更多FPGA相关源码: 1.前言 Matlab里面计算通常用的是浮点数,而FPGA在做数字信号处理时,为了节约资源,常常使用的是定点数。在实践中,我们经常需要将Matlab实现中的算法,用FPGA进行实现。 …

高效训练超越LoRA,北航发布MoRA

什么!LoRA我都没有学懂,又出现了MoRA??? LoRA作为当下最火热的大语言模型参数高效微调技术,正在以前所未有的速度迭代更新。从最初的LoRA到陆续推出的LoRA、DoRA、AsyLoRA等变体,LoRA家族可谓是…

深入探究 threejs 中的材质与纹理应用

深入探究 threejs 中的材质与纹理应用 一、引言 在三维图形开发领域,Three.js 是一个强大而受欢迎的库。其中,材质与纹理的应用对于创建逼真和吸引人的三维场景起着至关重要的作用。通过对材质和纹理的巧妙运用,可以极大地增强模型的视觉效…

C# WinForm —— 26 ImageList 介绍

1. 简介 图片集合,用于存储图像的资源,并在关联控件中显示出来 可以通过 索引、键名 访问每张图片 没有事件 2. 属性 属性解释(Name)控件ID,在代码里引用的时候会用到,一般以 imgList 开头ClolorDepth用于呈现图像的颜色数,默…

【开源】Wordpress自定义鼠标样式插件

插件简介 使用此插件可一键自定义Wordpress前端鼠标指针样式。利用该插件,站长可以快速实现替换多种鼠标指针样式于网站前端。 鼠标图案均来自于网络,插件仅作收集整理,插件完全开源无任何商业性质。 插件截图 使用教程 下载插件文件 下载…

Mybatis第一讲——你会Mybatis吗?

文章目录 什么是MybatisMybatis的作用是什么 Mybatis 怎么使用注解的方式注解的多种使用Options注解ResultType注解 XML的方式update标签 #{} 和 ${}符号的区别#{}占位${}占位 ${}占位的危险性(SQL注入)数据库连接池 什么是Mybatis 首先什么是Mybatis呢?Mybatis是一…

Ps:调整画笔工具

调整画笔工具 Adjustment Brush Tool可以将选区、创建蒙版和应用调整的传统工作流程合并为一个步骤,简化了对图像进行非破坏性局部调整的操作。 快捷键:B 调整画笔工具是 Photoshop 2024 年 5 月版(25.9 版)新增的工具。 ◆ ◆ …

Stable Diffusion生成图片的参数查看与抹除方法

前几天分享了几张Stable Diffusion生成的艺术二维码,有同学反映不知道怎么查看图片的参数信息,还有的同学问怎么保护自己的图片生成参数不会泄露,这篇文章就来专门分享如何查看和抹除图片的参数。 查看图片的生成参数 1、打开Stable Diffus…

Redis常用命令——List篇

提到List,我们第一时间想到的就是链表。但是在Redis中,List更像是一种双端队列,例如C中的deque。它可以快速高效的对头部和尾部进行插入和删除操作。本片文章主要对List列表的相关命令进行详解,希望本篇文章会对你有所帮助。 文章…

vscode常用插件及插件安装方式

一、常用插件 Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code 说明:中文语言包扩展(简体) open in browser 说明:可以在默认浏览器或应用程序中打开当前文件 Auto Rename Tag 说明:自动重…

pyqt 进度条QProgressBar

pyqt 进度条 QProgressBar效果代码 QProgressBar 在 PyQt 应用程序中,进度条(通常称为 QProgressBar)是一个用于显示任务进度的控件。它可以显示一个水平或垂直的条形图,条形图的长度会随着进度的增加而增加。 QProgressBar 的主…

C语言---文件操作

【C语言详解】——文件操作&#xff08;建议收藏&#xff09;_c语言 写文件原理-CSDN博客 一、文件的读取 # define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<errno.h> #include<string.h>int main() {FILE * pffopen("C:\\Users\\zhw\\De…

【电路笔记】-带阻滤波器

带阻滤波器 文章目录 带阻滤波器1、概述2、典型带阻滤波器配置3、带阻滤波器示例14、陷波滤波器5、带阻滤波器示例26、总结带阻滤波器也称为陷波滤波器,阻止并拒绝位于其两个截止频率点之间的频率,并传递该范围两侧的所有这些频率。 1、概述 通过将基本 RC 低通滤波器与 RC …

Python自动实时查询预约网站的剩余名额并在有余额时发邮件提示

本文介绍基于Python语言&#xff0c;自动、定时监测某体检预约网站中指定日期的体检余额&#xff0c;并在有体检余额时自动给自己发送邮件提醒的方法。 来到春招末期&#xff0c;很多单位进入了体检流程。其中&#xff0c;银行&#xff08;尤其是四大行&#xff09;喜欢“海检”…

springboot基础及上传组件封装

简介 本文主要以文件上传为demo&#xff0c;介绍了一些 springboot web 开发的入门的技术栈。 对应刚接触 springboot 的可以参考下。 主要包括文件md5比对、生成图片缩略图、数据库迁移、文件记录持久化、请求全局异常处理等功能。 准备工作 在 idea 中创建项目&#xff…

十大排序 —— 快速排序

十大排序 —— 快速排序 快速排序一些坑快速排序的性能优点&#xff1a;缺点&#xff1a;性能优化&#xff1a; 我们今天来看看十大排序中很出名的一个算法——快速排序&#xff1a; 快速排序 快速排序&#xff08;Quick Sort&#xff09;是一种经典的、高效的排序算法&#…

centos8stream 编译安装 php-rabbit-mq模块

官方GitHub&#xff1a;https://github.com/php-amqp/php-amqp 环境依赖安装 dnf install cmake make -y 1.安装rabbitmq-c cd /usr/local/src/ wget https://github.com/alanxz/rabbitmq-c/archive/refs/tags/v0.14.0.tar.gz tar xvf v0.14.0.tar.gz cd rabbitmq-c-0.14.0/…

Linux下多线程的相关概念

&#x1f916;个人主页&#xff1a;晚风相伴-CSDN博客 &#x1f496;如果觉得内容对你有帮助的话&#xff0c;还请给博主一键三连&#xff08;点赞&#x1f49c;、收藏&#x1f9e1;、关注&#x1f49a;&#xff09;吧 &#x1f64f;如果内容有误或者有写的不好的地方的话&…

php反序列化入门

一&#xff0c;php面向对象。 1.面向对象&#xff1a; 以“对象”伪中心的编程思想&#xff0c;把要解决的问题分解成对象&#xff0c;简单理解为套用模版&#xff0c;注重结果。 2.面向过程&#xff1a; 以“整体事件”为中心的编程思想&#xff0c;把解决问题的步骤分析出…

实时监控电脑屏幕的软件是什么?三款超受欢迎的电脑监控软件

实时监控电脑屏幕的软件在现代企业管理中扮演着至关重要的角色&#xff0c;它们不仅帮助管理者实时监控员工的工作状态&#xff0c;提高工作效率&#xff0c;还通过数据分析和报告功能&#xff0c;为企业提供了优化管理流程和决策支持的依据。以下将介绍几款市面上广泛使用的实…