搜狐三面:说说你是怎么解决MySQL死锁问题的!腾讯云开发者社区

死锁是并发系统中常见的问题,同样也会出现在数据库MySQL的并发读写请求场景中。当两个及以上的事务,双方都在等待对方释放已经持有的锁或因为加锁顺序不一致造成循环等待锁资源,就会出现“死锁”。常见的报错信息为”Deadlockfoundwhentryingtogetlock...”。

举例来说A事务持有X1锁,申请X2锁,B事务持有X2锁,申请X1锁。A和B事务持有锁并且申请对方持有的锁进入循环等待,就造成了死锁。

如上图,是右侧的四辆汽车资源请求产生了回路现象,即死循环,导致了死锁。

从死锁的定义来看,MySQL出现死锁的几个要素为:

a.两个或者两个以上事务

b.每个事务都已经持有锁并且申请新的锁

c.锁资源同时只能被同一个事务持有或者不兼容

d.事务之间因为持有锁和申请锁导致彼此循环等待

说明:后续内容实验环境为5.7版本,隔离级别为RR(可重复读)

为了分析死锁,我们有必要对InnoDB的锁类型有一个了解。

MySQLInnoDB引擎实现了标准的行级别锁:共享锁(Slock)和排他锁(Xlock)

如果事务T1持有行r的S锁,那么另一个事务T2请求r的锁时,会做如下处理:

如果T1持有r的X锁,那么T2请求r的X、S锁都不能被立即允许,T2必须等待T1释放X锁才可以,因为X锁与任何的锁都不兼容。共享锁和排他锁的兼容性如下所示:

间隙锁锁住一个间隙以防止插入。假设索引列有2,4,8三个值,如果对4加锁,那么也会同时对(2,4)和(4,8)这两个间隙加锁。其他事务无法插入索引值在这两个间隙之间的记录。但是,间隙锁有个例外:

next-keylock实际上就是行锁+这条记录前面的gaplock的组合。假设有索引值10,11,13和20,那么可能的next-keylock包括:

(负无穷,10]

(10,11]

(11,13]

(13,20]

(20,正无穷)

在RR隔离级别下,InnoDB使用next-keylock主要是防止幻读问题产生。

InnoDB为了支持多粒度的加锁,允许行锁和表锁同时存在。为了支持在不同粒度上的加锁操作,InnoDB支持了额外的一种锁方式,称之为意向锁(IntentionLock)。意向锁是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁。意向锁分为两种:

由于InnoDB存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫描以外的任何请求。表级意向锁与行级锁的兼容性如下所示:

插入意向锁是在插入一行记录操作之前设置的一种间隙锁,这个锁释放了一种插入方式的信号,即多个事务在相同的索引间隙插入时如果不是插入间隙中相同的位置就不需要互相等待。假设某列有索引值2,6,只要两个事务插入位置不同(如事务A插入3,事务B插入4),那么就可以同时插入。

横向是已持有锁,纵向是正在请求的锁:

一个温馨小提示:xmen平台支持查看死锁主库的死锁日志,访问方式如下:

在进行具体案例分析之前,咱们先了解下如何去读懂死锁日志,尽可能地使用死锁日志里面的信息来帮助我们来解决死锁问题。

后面测试用例的数据库场景如下:

MySQL5.7事务隔离级别为RR

表结构和数据如下:

通过执行showengineinnodbstatus可以查看到最近一次死锁的日志。

***(1)TRANSACTION:

TRANSACTION2322,ACTIVE6secstartingindexread

事务号为2322,活跃6秒,startingindexread表示事务状态为根据索引读取数据。常见的其他状态有:

mysqltablesinuse1说明当前的事务使用一个表。

locked1表示表上有一个表锁,对于DML语句为LOCK_IX

LOCKWAIT2lockstruct(s),heapsize1136,1rowlock(s)

LOCKWAIT表示正在等待锁,2lockstruct(s)表示trx->trx_locks锁链表的长度为2,每个链表节点代表该事务持有的一个锁结构,包括表锁,记录锁以及自增锁等。本用例中2locks表示IX锁和lock_modeX(Next-keylock)

1rowlock(s)表示当前事务持有的行记录锁/gap锁的个数。

MySQLthreadid37,OSthreadhandle140445500716800,queryid1234127.0.0.1rootupdating

MySQLthreadid37表示执行该事务的线程ID为37(即showprocesslist;展示的ID)

deletefromstudentwherestuno=5表示事务1正在执行的sql,比较难受的事情是showengineinnodbstatus是查看不到完整的sql的,通常显示当前正在等待锁的sql。

***(1)WAITINGFORTHISLOCKTOBEGRANTED:

RECORDLOCKSspaceid11pageno5nbits72indexidx_stunooftablecw**.**studenttrxid2322lock_modeXwaiting

RECORDLOCKS表示记录锁,此条内容表示事务1正在等待表student上的idx_stuno的X锁,本案例中其实是Next-KeyLock。

事务2的log和上面分析类似:

***(2)HOLDSTHELOCK(S):

RECORDLOCKSspaceid11pageno5nbits72indexidx_stunooftablecw**.**studenttrxid2321lock_modeX

显示事务2的insertintostudent(stuno,score)values(2,10)持有了a=5的LockmodeX

|LOCK_gap,不过我们从日志里面看不到事务2执行的deletefromstudentwherestuno=5;

这点也是造成DBA仅仅根据日志难以分析死锁的问题的根本原因。

***(2)WAITINGFORTHISLOCKTOBEGRANTED:

RECORDLOCKSspaceid11pageno5nbits72indexidx_stunooftablecw**.**studenttrxid2321lock_modeXlocksgapbeforerecinsertintentionwaiting

表示事务2的insert语句正在等待插入意向锁lock_modeXlocksgapbeforerecinsertintentionwaiting(LOCK_X+LOCK_REC_gap)

重点说明下delete不存在的记录是要加上gap锁,事务日志中显示lock_modeXlocksgapbeforerec.

记录不存在,导致T2先持有了(lock_modeXlocksgapbeforerec)锁住

(2,20,1,1,’ratail’,1,0)-(3,30,1,’retail’,1,0)的区间,防止符合条件的记录插入。

总结来说,就是T1(insert)等待T2(delete),T2(insert)等待T1(delete)故而循环等待,出现死锁。

表结构和数据如下所示:

1.事务T2insertintot7(id,a)values(26,10)语句insert成功,持有a=10的排他行锁(X

locksrecbutnogap)

2.事务T1insertintot7(id,a)values(30,10),因为T2的第一条insert已经插入a=10的记录,

事务T1inserta=10则发生唯一键冲突,需要申请对冲突的唯一索引加上SNext-keyLock

(即lockmodeSwaiting)这是一个间隙锁会申请锁住(,10],(10,20]之间的gap区域。

3.事务T2insertintot7(id,a)values(40,9)该语句插入的a=9的值在事务T1申请的gap锁

4,10之间,故需事务T2的第二条insert语句要等待事务T1的S-Next-keyLock锁释放,

在日志中显示lock_modeXlocksgapbeforerecinsertintentionwaiting。

首先要理解的是对同一个字段申请加锁是需要排队的。

其次表tx中索引idx_c1为非唯一普通索引。

(1).T2执行selectforupdate操作持有记录id=30的主键行锁:PRIMARYoftabletest.txtrxid2077lock_modeXlocksrecbutnotgap。

(2).T1语句update通过普通索引idx_c1更新c2,先获取idx_c1c1=5的X锁lock_modeXlocksrecbutnotgap,然后去申请对应主键id=30的行锁,但是T2已经持有主键的行数,于是T1等待。

(3).T2执行根据主键id=30删除记录,需要申请id=30的行锁以及c1=5的索引行锁。但是T1尚及持有该锁,故会出现indexidx_c1oftabletest.txtrxid2077lock_modeXlocksrecbutnotgapwaiting.

T2(delete)等待T1(update),T1(update)等待T2(selectforupdate)循环等待,造成死锁。

可以看到两个事务update不存在的记录,先后获得间隙锁(gap锁),gap锁之间是兼容的所以在update环节不会阻塞。两者都持有gap锁,然后去竞争插入意向锁。当存在其他会话持有gap锁的时候,当前会话申请不了插入意向锁,导致死锁。

1.合理的设计索引,区分度高的列放到组合索引前面,使业务SQL尽可能通过索引定位更少的行,减少

锁竞争。

3.避免大事务,尽量将大事务拆成多个小事务来处理,小事务发生锁冲突的几率也更小。

4.以固定的顺序访问表和行。比如两个更新数据的事务,事务A更新数据的顺序为1,2;事

务B更新数据的顺序为2,1。这样更可能会造成死锁。

5.在并发比较高的系统中,不要显式加锁,特别是是在事务里显式加锁。如select…for

update语句,如果是在事务里(运行了starttransaction或设置了autocommit等于0),

那么就会锁定所查找到的记录。

6.尽量按主键/索引去查找记录,范围查找增加了锁冲突的可能性,也不要利用数据库做一些

额外额度计算工作。比如有的程序会用到“select…where…orderbyrand();”

这样的语句,由于类似这样的语句用不到索引,因此将导致整个表的数据都被锁住。

7.优化SQL和表设计,减少同时占用太多资源的情况。比如说,减少连接的表,将复杂SQL

THE END
1.死字是什么结构的死字的结构死字是左右结构,部件拆解为歹、匕。详细解释指丧失生命。https://edu.iask.sina.com.cn/jy/fAQTbOZWLJ.html
2.死是什么意思死的解释死怎么读死是什么意思死的解释 死怎么读 「死」怎么读拼音 汉字死 拼音 sǐ 怎么读 部首歹(左右结构) 笔画数6 五行金 死的意思解释 「死」 拼音:[sǐ] 怎么读: 1. (生物)失去生命(跟“生、活”相对)。【组词】死亡。死人。这棵树死了。死棋。死火山。 2. 不顾生命;拼死。【组词】死战。死守。 3. https://zidian.bi0.cn/6B7B__xinhua.html
3.死字取名寓意死字的意思死字取名的含义是什么死的拼音:sǐ,上声调,声母为sh,韵母为ǐ。 死的繁体字:死 (为本体字即无繁体字)。 死的部首:歹部。 死的笔画:6画;死字繁体字多少画:6画;死字康熙字典多少画:6画。 死的笔顺:一ノフ丶ノフ,书写为横、撇、横撇、点、撇、横撇。 死字五行属什么:属金;与死字相同五行属金的起名用字有:玉、小、金https://zd.liemingwang.com/detail/si_9044.html
4.死字是什么结构的字体(死字是什么结构)目前关于大家提出的死字是什么结构这个问题,大家都希望能够得到一个答案,那么小编今天就去收集了一些死字是什么结构相关的内容来分享给大家,如果大家感兴趣的话可以接着往下看。 “死”字由“歹”和“匕”组成; “歹”就是“上”去掉下边一横再加“夕”的那个字的今字,本义是尸骨; https://www.gyscw.com/zsbk/202310/410175.html
5.“死”字的结构杜永道<正>杜老师:在教学中,大多数老师认为"死"这个字是独体字,也有老师认为是半包围结构,因为在查字典的过程中,知道这个字既可以查"一"字部,又可以查"歹"字部。这个字究竟是什么结构呢?敬请赐教。谢谢!安徽省阜阳市太和三中附小 著录项 来源 《小学语文教师》 |2014年第2期|76-76|共1页 作者 杜永道;https://www.zhangqiaokeyan.com/academic-journal-cn_primary-school-language-teacher_thesis/0201249677019.html
6.“死”字的结构yuejie岁月在教学中,大多数教师认为“死”这个字是独体字,也有教师认为是半包围结构,因为在查字典的过程中,知道这个字既可以查“一”字部,又可以查“歹”字部。这个字究竟是什么结构呢?“死”是常用字,在2009年颁布的《现代常用独体字规范》中没有“死”,可见“死”不是独体字。“死”在《现代汉语词典》中属“歹https://blog.sina.cn/dpool/blog/s/blog_605062620101ghjv.html
7.《古代汉语》课程教学大纲第一节“者”字结构 第二节“所”字结构 第八章 特殊的句法结构(下) 第一节以表达直陈语气为常的结构 一、[以……为……] 二、[以为] 第二节以表达疑问语气为常的结构 一、[何为] [奚为] 二、[奈何][如何][若何][奈……何][如……何][若……何][何如][何若] https://wenxueyuan.jsu.edu.cn/info/1129/10719.htm
8.构死(構死)的意思构死是什么意思构死的含义构死的寓意⒈ 诬陷而死。 什么是构死引证解释 ⒈ 诬陷而死。 引《新唐书·刘幽求传》:“既,五王皆为 三思 构死。” 构的拼音和组词语 构 构的拼音:gòu构的注音:ㄍㄡˋ构的简体笔画:8画 构的五行:木构的吉凶:平构的繁体笔画:0画 构的部首:木构的结构:左右结构构的繁体字:構 https://cidian.yw11.com/ci/%E6%9E%84%E6%AD%BB
9.python程序的流程控制实验结论python流程控制单if分支结构 if与else连用 if elif else 三者连用 if判断之嵌套 while循环 while+break break跳出本层循环详解 全局标志位 while+continue while+else 死循环 for循环 range关键字 for+break for+continue for+else for循环的嵌套使用小例子 结语 什么是流程控制 https://blog.51cto.com/u_13633/8045169
10.2023Web前端开发八股文&面试题(万字系列)——这篇就够了!易于用户阅读,样式丢失的时候能让页面呈现清晰的结构 有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重 方便屏幕阅读器解析,如盲人阅读器根据语义渲染网页 有利于开发和维护,语义化更具可读性,代码更好维护,与CSS3关系更和谐 1.5 引入样式时,link和@import的区别? https://developer.aliyun.com/article/1353677
11.死字笔顺笔画顺序死字怎么写 「死」字是左右结构,笔画数:6。 问:死的第1笔是什么笔画?答:横【一】。 问:死的第2笔是什么笔画?答:撇【丿】。 问:死的第3笔是什么笔画?答:横撇/横钩【?】。 问:死的第4笔是什么笔画?答:点【丶】。 问:死的第5笔是什么笔画?答:撇【丿】。 https://bihua.gei6.com/sizibishun__i90ufln4.html
12.死是什么结构什么偏旁理想股票技术论坛死是什么结构什么偏旁,这里主要探讨汉字的字形结构以及汉字构造的基本原理,包括了偏旁部首的作用和字形组成的规律。通过研究字形结构和偏旁部首,可以更好地理解和学习汉字的形态和意义。 ,理想股票技术论坛https://www.55188.com/tag-thread-1701401-1.html
13.“死”字是结构,读音是,它的第五笔是。——青夏教育精英家教网网址:http://www.1010jiajiao.com/paper/timu/570833.html[举报] 1、“死”字是___结构,读音是___,它的第五笔是___。 题目来源:28 浅水洼里的小鱼 试卷相关题目 乎( ) 至( ) 脸( ) 粒( ) 呼( ) 致( ) 捡( ) 粉( ) yǒng jiǔ shēng sǐ yāo bèi bèi zi kē lì ( ) ( http://www.1010jiajiao.com/paper/timu/570833.html
14.ORACLE数据库入门oracle触发器不加foreachrow(3)loop(死循环)循环结构 declare inumber:=0; begin loop i :=i+1; DBMS_OUTPUT.PUT_LINE('我好帅'); exitwheni>=100;//退出条件 endloop; end; (4) while循环 declare inumber:=0; begin while i<100 loop i :=i+1; DBMS_OUTPUT.PUT_LINE(i); https://blog.csdn.net/m0_61857264/article/details/123119895
15.汉藏语声调探源前字和后字如果将平、上、去、入任意搭配,可得16种格式,然而大量出现的只有上列这10种,而上平、去上、去平、入去、入上、入平很少见,换言之,在并列结构里,上、去、入3个调的字一般不排在平声字之前,去、入两个调的字一般不排在上声字之前,入声字一般不排在去声字之前。所以选择并列结构的前字时,平声https://zangdiyg.com/home/article/detail/id/6549.html
16.死字笔画结构死字笔画结构相关介绍,死字笔画结构是什么意思,死字笔画结构都有什么,死字笔画结构的具体由来https://www.xdyy8.com/tag/szbhjg.html