Mysql死锁问题分析解决

一.问题背景

1.什么是死锁(Deadlock)

摘抄网上死锁的定义:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。
简而言之,就是我和你都拿到某个资源,我需要等你手中的资源释放以后我才能去干接下来的活,你也需要等我手中的资源释放之后才能去继续干接下来的活,这样就好了,咱俩就一直等着吧,就形成了死锁,如果没有外力打破这种互相等待的尴尬,那么死锁就会一直持续下去。

2.形成死锁的条件

这一段也就在网上找的解释,大家看看就好,理解就行
(1)互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
(2)请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
(3)不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
(4)环路等待条件:是指进程发生死锁后,必然存在一个进程--资源之间的环形链

3.Mysql死锁

好的,介绍了一下死锁的相关知识,咱们进入一下正题,数据库死锁。数据库为什么发生死锁,发生数据库死锁有什么前提条件是什么呢?
首先,数据库发生死锁的前提,多个事务都持有同一种不互斥(互斥排他锁是不能同时存在的)锁,还都在等待对方释放锁,继续执行,这样就造成了数据库的死锁。不过好在,Mysql自己实现一种死锁检测机制,如果监测到有死锁的存在时,mysql会主动中断一个事务,这个事务失败退出后,打破了死锁形成的必要条件,那么另外的事务就会继续执行下去。
综上,在解决Mysql死锁之前,我们必须要对Mysql的各种锁有了解,分析数据库语句执行的时候,Mysql会不会加上锁,会加哪些锁?(因为Mysql锁的知识比较复杂,如果下面说的有错误的话,请大家见谅)

二.Mysql锁知识介绍

在介绍锁之前,大家需要知道Mysql的四种隔离级别,隔离级别不同,锁也是不一样的,网上相关知识有很多,就不多说了,推荐大家读一篇博客:http://hedengcheng.com/?p=771,虽然大神对锁有了很详细的解读,但是每个人可能理解成都都不一样,下面就是个人的一些理解,本文都采用的是mysql默认的隔离级别,可重复可(RR)。

1.锁的分类(具体的一些定义,大家自己去查一下,了解一下)

1.全局锁(数据库级别,做逻辑备份使用)
2.表级锁(意向共享锁(IS)、意向排他锁(IX))
3.行锁(共享锁(S)、排他锁(X)、间隙锁(GAP)、next-lock-key(间隙锁加行锁))
全局锁一般接触的比较少,可能都是DBA进行数据库逻辑备份的时候用的,我没用过。而行锁的话,是有数据库引擎自己实现的,众所周知,mysql有俩种搜索引擎InnoDb和 MyISAM 而后者是不支持行锁的,所以下面的行锁分析都是按照InnoDb引擎的分析的,下面是各种锁的冲突关系示意图。


image.png
2.锁的两阶段提交

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。所以一般在进行事务的时候,需要把加锁多,锁粒度大的语句放在事务的最后执行。

3.快照读和当前读

在理解这个之前,我们得要了解Mysql的MVCC(多版本并发控制)这种机制相当于一种乐观锁的实现,根据不同时间点保存数据快照,同一个事务看到的快照是一样的。
快照读:读的是快照,无需加锁,普通的数据库查询语句
当前读:读的是当下的数据,需要进行加锁(删除、更新、插入等都属于)

3.Mysql并发死锁案例分析

首先,Mysql对加行锁有如下的一个规则:
行锁,锁的是索引的值。如果没有条件行没有索引的话,那么就会走隐藏的聚簇索引。有个特殊的就是,如果没有走索引条件的话,就会进行全局扫描,这时候就相当于加了表锁。
下面就分析一下真实遇到的并发死锁案例分析
建表语句如下:

CREATE TABLE `lock_test` (
  `id` int NOT NULL,
  `c` int DEFAULT NULL,
  `d` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_id_c` (`id`,`c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

遇到的这种情况,是由于程序并发执行,插入相同的一条sql语句,示意图如下:


image.png

下面就分析一下为什么会出现死锁:
T1时刻,会话A插入一条记录,插入之后在加上记录锁(相当于排他锁(X锁)),T2时刻,因为存在唯一键冲突,会加上读锁(S锁),在插入的时候,发现会话A持有X锁,获取锁阻塞,同理T3时刻,会话C也出现阻塞等待X锁的情况。T4时刻,会话A发生回滚,释放X锁,此时会话B想获得X锁,但发现会话C有S锁存在,俩者冲突,同理会话C也在等待会话B的S锁,所以俩者产生了死锁。
由于Mysql有自己的死锁检测机制和解决机制,会话C失败推出,会话B正常执行插入操作,至此,死锁分析结束。

四.死锁解决方案

由唯一索引引起的死锁问题,归根到底,是由于并发请求造成的,无非是由于前端重复请求或者是网络抖动产生的,下面就介绍俩种解决方案。

1.缓存去重(推荐)

因为是并发请求,所以打到后端的请求参数都一样,为了防止并发请求造成并发数据库请求,我们可以在service层加一层缓存,把重复的请求给过滤掉,确保只放入一个请求进入,伪代码如下:

String key = id+c+d;
if(redisClient.exits(key)){
//并发请求,直接返回
return;
}
//唯一请求,过期时间根据实际情况而定
redisClient.sexEx(key,value,expireTime);
//数据库插入操作
dao.insert
2.异常捕捉

因为Mysql自己有死锁检测和恢复机制,所以即使发生了死锁,肯定有一条插入请求会落库成功,所以这时候只需要把死锁异常给catch住,让程序继续运行下去,不崩即可,伪代码就不写了,加个try、catch就行了。

五 总结

Mysql锁的知识还是很多的,还需要继续深入地了解,比如说insert还需要插入意向锁等。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • 1 MySQL的三种锁 1.1 表锁 开销小,加锁快 不会出现死锁 锁定粒度大,发生锁冲突的概率最高,并发度最低 ...
    JavaEdge阅读 643评论 0 1
  • 1、竞态条件: 定义:竞态条件指的是一种特殊的情况,在这种情况下各个执行单元以一种没有逻辑的顺序执行动作,从而导致...
    Hughman阅读 1,286评论 0 7
  • 一. 背景知识 InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级...
    爱情小傻蛋阅读 791评论 0 2
  • 死锁产生的原因和解锁的方法 产生死锁的四个必要条件: (1) 互斥条件:一个资源每次只能被一个进程使用。 (2) ...
    憩在河岸上的鱼丶阅读 1,477评论 0 4
  • 我和石敏相视坐在咖啡桌的两端,玩着儿时的飞行棋,随口抱怨月河的这条河真的是不太清澈。 咖啡馆里空调很足,她脱下大衣...
    衬衫当外套阅读 279评论 0 0