MySQL 加锁和死锁解析

原文:MySQL 加锁和死锁解析

目录

  • 产生死锁的必要条件
  • 锁是加在那里的?
  • 操作与加锁的对照关系
    • Insert
    • Delete
    • Update
    • GAP锁
    • 什么时候加next-key lock?
    • Insert Intention Lock
  • 总结


产生死锁的必要条件

  • 多个并发事务(2个或者以上)
  • 每个事物都持有了锁(或者是已经在等待锁)
  • 每个事务都需要再继续持有锁(为了完成事务逻辑,还必须更新更多的行)
  • 事物之间产生加锁的循环等待,形成死锁

    常规锁模式

  • LOCK_S(读锁,共享锁)
  • LOCK_X(写锁,排它锁)

    锁的属性

  • LOCK _REC_NOT_GAP(锁记录)
  • LOCK_GAP(锁记录前的GAP)
  • LOCK_ORDINARY(同时锁记录+记录前的GAP,Next key锁)
  • LOCK_INSERT_INTETION(插入意向锁)

    锁组合(属性+模式)

    可以任意组合

    锁冲突矩阵

锁是加在那里的?

  • 根据主键查找-锁加在主键上

    如 begin;select * from tt_copy where id=4 for update;

    加锁情况

    index PRIMARY of table test.tt_copy trx id 1101588 lock_mode X locks rec but not gap

  • 根据普通索引查找-锁加在普通索引和主键上

    如 begin;select * from tt_copy force index(idx_a) where a=4 for update;

    加锁情况

    index idx_a of table test.tt_copy trx id 1101590 lock_mode X locks rec but not gap

    index PRIMARY of table test.tt_copy trx id 1101590 lock_mode X locks rec but not gap

操作与加锁的对照关系

以下没特殊说明都为RC隔离级别

Insert

  • 无Unique key,插入后 :无论RC或RR隔离级别都是对主键加 LOCK_X+LOCK_REC_NOT_GAP
  • 有Unique key

    插入前,唯一约束检查:LOCK_S+LOCK_ORDINARY

    插入前,插入的位置有GAP锁:LOCK_INSERT_INTETION

    插入后,新数据插入:LOCK_X+LOCK_REC_NOT_GAP

Delete

满足删除条件的所有记录:LOCK_X+LOCK_REC_NOT_GAP

Update

Update操作分解

  • Step 1:定位到 下一条满足查询条件的记录(查询过程,类似于Select/Delete)
  • Step 2:删除当前定位到的记录(标记为删除状态)
  • Step 3:拼装更新后项,根据更新后项定位到 新的插入位置
  • Step 4:在新的插入位置,判断是否存在 Unique 冲突( 存在Unique Key 时
  • Step 5:插入更新后项(不存在Unique冲突时)
  • Step 6: 重复Step 1 到Step 5 的操作,直至扫描完整个查询范围

Update操作分析

  • Step 1,Step 2:Delete
  • Step 3,Step 4,Step 5:Insert

Update

  • 无Unique key:

    • 查询范围中的所有记录,LOCK_X + LOCK_REC_NOT_GAP
  • 有Unique key:
    • 查找满足条件的记录:查询范围内的所有记录, LOCK_X + LOCK_REC_NOT_GAP
    • 更新后项存在唯一性冲突:冲突项上的加锁,LOCK_S + LOCK_ORDINARY
    • 更新后项不存在唯一性冲突: 更新位置后项加锁,LOCK_S + LOCK_GAP (省略)
    • 实际更新操作:可看做插入了一条新纪录,LOCK_X + LOCK_REC_NOT_GAP

GAP锁

那些操作会加GAP锁?

  • Read Committed (RC) ) :Unique Key 唯一约束检查;Purge操作;
  • Repeatable Read (RC ):RC的基础上,所有需要加锁的索引范围扫描和索引查找(Update/Delete…)
  • 还有一种会加GAP锁:RR隔离级别下,对有唯一索引的表执行insert on duplicate update操作,除了会对新插入的记录加x not gap外,还会对相邻记录加x gap

如何去掉GAP锁?

change the transaction isolation level to READ COMMITTED or enable the innodb_locks_unsafe_for_binlog system variable (which is now deprecated)

什么时候加next-key lock?

By default, InnoDB operates in REPEATABLE READ transaction isolation level. In this case, InnoDB uses next-key locks for searches and index scans, which prevents phantom rows

Insert Intention Lock

An insert intention lock is a type of gap lock set by INSERT operations prior to(在...之前) row insertion.

总结

? 原则之一

  • 要分析一个死锁,必须深入业务,了解整个事务的逻辑(闭门无法造车)

? 原则之二`

  • GAP锁很复杂,为了减少GAP锁,减少GAP导致的死锁,尽量选择Read Committed隔离级别(RC + row based binlog,基本上能够解决所有问题,无需使用Repeatable Read)
  • 适当的 减少Unique 索引,能够减少GAP锁导致的死锁(根据业务情况而定)

? 原则之三

  • 在MySQL 中,以不同索引的过滤条件, 来操作相同的记录(Update/Delete ),很容易产生死

    锁。

? 原则之四

  • RC隔离级别下,如果死锁中出现Next Key(Gap锁),说明表中一定存在unique索引
  • 多语句事务产生的死锁,确保每条语句操作记录的顺序性,能够极大减少死锁


本文大多数都整理自《死锁-何登成 - 管中窥豹——MySQL(InnoDB)死锁分析之道》

原文地址:https://www.cnblogs.com/lonelyxmas/p/10891650.html

时间: 2024-10-14 09:58:25

MySQL 加锁和死锁解析的相关文章

MySQL 加锁处理分析

1    背景    1 1.1    MVCC:Snapshot Read vs Current Read    2 1.2    Cluster Index:聚簇索引    3 1.3    2PL:Two-Phase Locking    3 1.4    Isolation Level    4 2    一条简单SQL的加锁实现分析    5 2.1    组合一:id主键+RC    6 2.2    组合二:id唯一索引+RC    6 2.3    组合三:id非唯一索引+RC 

【转载】MySQL 加锁处理分析

1    背景    1 1.1    MVCC:Snapshot Read vs Current Read    2 1.2    Cluster Index:聚簇索引    3 1.3    2PL:Two-Phase Locking    3 1.4    Isolation Level    4 2    一条简单SQL的加锁实现分析    5 2.1    组合一:id主键+RC    6 2.2    组合二:id唯一索引+RC    6 2.3    组合三:id非唯一索引+RC 

Mysql加锁过程详解

1.背景 MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备就MySQL/InnoDB的加锁问题,展开较为深入的分析与讨论,主要是介绍一种思路,运用此思路,拿到任何一条SQL语句,都能完整的分析出这条语句会加什么锁?会有什么样的使用风险?甚至是分析线上的一个死锁场景,了解死锁产生的原因. 注:MySQL是一个支持插件式存储引擎的数据库系统.本文下面的所有

MySQL加锁分析

参考:MySQL 加锁处理分析.该文已经讲的很详尽了,也易懂,下面仅仅是个人做的总结. 一. 背景 1.1 隔离级别 1.2 加锁过程 逐条处理,逐条加锁. 1.3 两阶段锁2PL 1.4 gap锁 gap锁是间隙锁,即相邻两条有效记录间隙的锁(锁的是间隙),它是针对insert的,用来解决幻读的发生.它会阻塞insert,但不会阻塞delete/update等(记录本来也不存在). RC与RR的重要区别就是幻读.所以RR才需要引入gap锁. 二.加锁组合分析 说加什么锁,首先要了解两个前提:1

MySQL 加锁处理分析 转

MySQL 加锁处理分析  转 http://hedengcheng.com/?p=771 十二 13th, 2013 发表评论 | Trackback 1    背景    1 1.1    MVCC:Snapshot Read vs Current Read    2 1.2    Cluster Index:聚簇索引    3 1.3    2PL:Two-Phase Locking    3 1.4    Isolation Level    4 2    一条简单SQL的加锁实现分析 

(转)MySQL 加锁处理分析

MySQL 加锁处理分析 原文:http://hedengcheng.com/?p=771 1    背景    1 1.1    MVCC:Snapshot Read vs Current Read    2 1.2    Cluster Index:聚簇索引    3 1.3    2PL:Two-Phase Locking    3 1.4    Isolation Level    4 2    一条简单SQL的加锁实现分析    5 2.1    组合一:id主键+RC    6 2.

MySQL redo lock 死锁问题排查 & 解决过程

版权声明:本文由 MySQL redo lock 死锁问题排查 & 解决过程 张青林 原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/181 来源:腾云阁 https://www.qcloud.com/community 周一上班,首先向同事了解了一下上周的测试情况,被告知在多实例场景下 MySQL Server hang 住,无法测试下去,原生版本不存在这个问题,而新版本上出现了这个问题,不禁心头一颤,心中不禁感到奇怪

SQL Server锁分区特性引发死锁解析

原文:SQL Server锁分区特性引发死锁解析 锁分区技术使得SQL Server可以更好地应对并发情形,但也有可能带来负面影响,这里通过实例为大家介绍,分析由于锁分区造成的死锁情形. 前段时间园友@JentleWang在我的博客锁分区提升并发,以及锁等待实例中问及锁分区的一些特性造成死锁的问题,这类死锁并不常见,我们在这里仔细分析下.不了解锁分区技术的朋友请先看下我的锁分区那篇实例. Code(执行测试脚本时请注意执行顺序,说明) 步骤1 创建测试数据 use tempdb go creat

mysql group by 用法解析(详细)

在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供 有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值.其原因是 distinct只能返回它的目标字段,而无法返回其它字段,这个问题让我困扰了很久,用distinct不能解决的话,我只有用二重循环查询来解决,而 这样对于一个数据量非常大的站来说,无疑是会直接影响到效率的.所以我花了很多时间来研究这个问题,网上也查不到解决方案 下面先来看看例子: