图4 聚簇索引和二级索引

下面分析下索引和锁的关系。

1)delete from msg where id=2;

由于id是主键,因此直接锁住整行记录即可。

图5

2)delete from msg where token=’ cvs’;

由于token是二级索引,因此首先锁住二级索引(两行),接着会锁住相应主键所对应的记录;

图6

3)delete from msg where message=订单号是多少’;

message没有索引,所以走的是全表扫描过滤。这时表上的各个记录都将添加上X锁。

图7

1.2.2 锁与隔离级别的关系

大学数据库原理都学过,为了保证并发操作数据的正确性,数据库都会有事务隔离级别的概念:1)未提交读(Read uncommitted);2)已提交读(Read committed(RC));3)可重复读(Repeatable read(RR));4)可串行化(Serializable)。我们较常使用的是RC和RR。

提交读(RC):只能读取到已经提交的数据。

可重复读(RR):在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。

我们在1.2.1节谈论的其实是RC隔离级别下的锁,它可以防止不同事务版本的数据修改提交时造成数据冲突的情况,但当别的事务插入数据时可能会出现问题。

如下图所示,事务A在第一次查询时得到1条记录,在第二次执行相同查询时却得到两条记录。从事务A角度上看是见鬼了!这就是幻读,RC级别下尽管加了行锁,但还是避免不了幻读。

图8

innodb的RR隔离级别可以避免幻读发生,怎么实现?当然需要借助于锁了!

为了解决幻读问题,innodb引入了gap锁。

在事务A执行:update msg set message=‘订单’ where token=‘asd’;

innodb首先会和RC级别一样,给索引上的记录添加上X锁,此外,还在非唯一索引’asd’与相邻两个索引的区间加上锁。

这样,当事务B在执行insert into msg values (null,‘asd',’hello’); commit;时,会首先检查这个区间是否被锁上,如果被锁上,则不能立即执行,需要等待该gap锁被释放。这样就能避免幻读问题。

图9

3 死锁成因

了解了innodb锁的基本原理后,下面分析下死锁的成因。如前面所说,死锁一般是事务相互等待对方资源,最后形成环路造成的。下面简单讲下造成相互等待最后形成环路的例子。

3.1不同表相同记录行锁冲突

这种情况很好理解,事务A和事务B操作两张表,但出现循环等待锁情况。

图10

3.2相同表记录行锁冲突

这种情况比较常见,之前遇到两个job在执行数据批量更新时,jobA处理的的id列表为[1,2,3,4],而job处理的id列表为[8,9,10,4,2],这样就造成了死锁。

图11

3.3不同索引锁冲突

这种情况比较隐晦,事务A在执行时,除了在二级索引加锁外,还会在聚簇索引上加锁,在聚簇索引上加锁的顺序是[1,4,2,3,5],而事务B执行时,只在聚簇索引上加锁,加锁顺序是[1,2,3,4,5],这样就造成了死锁的可能性。

图12

3.4 gap锁冲突

innodb在RR级别下,如下的情况也会产生死锁,比较隐晦。不清楚的同学可以自行根据上节的gap锁原理分析下。

图13

4 如何尽可能避免死锁

1)以固定的顺序访问表和行。比如对第2节两个job批量更新的情形,简单方法是对id列表先排序,后执行,这样就避免了交叉等待锁的情形;又比如对于3.1节的情形,将两个事务的sql顺序调整为一致,也能避免死锁。

2)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。

3)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。

4)降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。

5)为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。

5 如何定位死锁成因

下面以本文开头的死锁案例为例,讲下如何排查死锁成因。

1)通过应用业务日志定位到问题代码,找到相应的事务对应的sql;

因为死锁被检测到后会回滚,这些信息都会以异常反应在应用的业务日志中,通过这些日志我们可以定位到相应的代码,并把事务的sql给梳理出来。

start tran1deleteHeartCheckDOByToken2updateSessionUser

...

commit

此外,我们根据日志回滚的信息发现在检测出死锁时这个事务被回滚。

2)确定数据库隔离级别。

执行select @@global.tx_isolation,可以确定数据库的隔离级别,我们数据库的隔离级别是RC,这样可以很大概率排除gap锁造成死锁的嫌疑;

3)找DBA执行下show InnoDB STATUS看看最近死锁的日志。

这个步骤非常关键。通过DBA的帮忙,我们可以有更为详细的死锁信息。通过此详细日志一看就能发现,与之前事务相冲突的事务结构如下:

这不就是图10描述的死锁嘛!

start tran1updateSessionUser2deleteHeartCheckDOByToken

...

commit

分布式锁能解决 mysql死锁吗_mysql死锁问题分析相关推荐

  1. mysql 1061原因_MySQL死锁问题分析及解决方法实例详解(转)

    出处:http://www.jb51.net/article/51508.htm MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下: 1.MySQL常用存储 ...

  2. Redisson(1)分布式锁——如何解决死锁问题

     Redisson是如何解决死锁问题的? 普通利用Redis实现分布式锁的时候,我们可能会为某个锁指定某个key,当线程获取锁并执行完业务逻辑代码的时候,将该锁对应的key删除掉来释放锁. lock- ...

  3. 分布式锁的实现- mysql

    前言 大家好,我是飓风,今天我们来聊聊分布式锁的原理.以及基于 mysql 怎么来实现分布式锁. 那么大家现在能不能想一想,分布式锁的使用场景都有哪些呢?下面我列举一些分布式锁的场景: 记住一点,一定 ...

  4. redis desktop manager_面试官:Redis分布式锁如何解决锁超时问题?

    Java面试笔试面经.Java技术每天学习一点 Java面试 关注不迷路 作者:wangzaiplus 来源:https://www.jianshu.com/u/8cb4591440ca 一.前言 关 ...

  5. redis续期_面试官:Redis分布式锁如何解决锁超时问题的?

    一.前言 关于redis分布式锁, 查了很多资料, 发现很多只是实现了最基础的功能, 但是, 并没有解决当锁已超时而业务逻辑还未执行完的问题, 这样会导致: A线程超时时间设为10s(为了解决死锁问题 ...

  6. mysql 死锁监控_mysql 死锁

    MySQL复制slave服务器死锁案例 原文:MySQL复制slave服务器死锁案例 MySQL复制刚刚触发了一个bug,该bug的触发条件是slave上Xtrabackup备份的时候执行flushs ...

  7. mysql可重复读和间隙锁_解决MySQL可重复读——详解间隙锁

    间隙锁(Gap Lock)是Innodb在可重复读提交下为了解决幻读问题时引入的锁机制,(下面的所有案例没有特意强调都使用可重复读隔离级别)幻读的问题存在是因为新增或者更新操作,这时如果进行范围查询的 ...

  8. mysql 死锁日志_Mysql死锁以及死锁日志分析

    死锁的概念 死锁:死锁一般是事务相互等待对方资源,***形成环路造成的. 对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行. 发生死锁会返回ERROR:1213 错误提示,大部分的死锁 ...

  9. mysql 死锁 代码_MySQL死锁问题解决的代码详细介绍

    一次MySQL死锁问题解决 一.环境CentOS, MySQL 5.6.21-70, JPA 问题场景:系统有定时批量更新数据状态操作,每次更新上千条记录,表中总记录数约为500W左右. 二.错误日志 ...

最新文章

  1. Python 学习笔记之字典(进阶篇)
  2. Linux 下 pmap 命令的使用
  3. 金融学习纲要与相关知识
  4. 基于sqlite数据库的C语言编程
  5. 2021抖音口腔护理行业洞察报告
  6. python闭包两种写法_浅析Python闭包
  7. docker-compose安装镜像
  8. dump分析工具_阿里P8教你如何使用Jprofile解析dump文件
  9. STM32工作笔记0099---Pacman常用命令
  10. 【IDEA】报错:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除
  11. vim 配置文件 (未完待续)
  12. Apache .htaccess Rewrite解决问号匹配的写法
  13. 《21天学通Java(第7版)》——VC程序员的学习笔记1
  14. Redis(九)-Redis的常用数据类型之Hash表
  15. 74HC573锁存器
  16. 团队任务5:事后诸葛亮会议
  17. 盘点一道使用Python编程来实现高斯计算的基础算术题目
  18. 2016.7.31整机升级计划
  19. 使用VMware安装Ubuntu虚拟机 - 完整教程
  20. c语言怎么取字符串首字母,C语言 字符串首字母转换成大写简单实例

热门文章

  1. Redis在Linux系统的配置优化
  2. 每日一皮:简历上写着熟练掌握…实际往往是这样的...
  3. 每日一皮:我靠,这个分枝真的merge回主干了!
  4. 每日一皮:高级开发员 VS 菜鸟开发员
  5. Sentinel Dashboard 中修改规则同步到 Nacos
  6. 上下定高 中间自适应_联合首发|医药供应链平台一块医药获新一轮融资,赋能产业上下游提质增效...
  7. 计科系大一c语言期末考试题,大一大学计算机基础期末考试试题「附答案」
  8. Window编译Opencv CUDA
  9. python 操作txt 写入列表
  10. goland os.Open 路径错误