参考文献

Mysql数据库中的各种锁_张花生的博客-CSDN博客_数据库锁


面试官:MySQL死锁有哪些场景?如何避免?


概述

相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。

一.导致锁表的原因

  • 锁表发生在insert,update,delete中

  • 锁表的原理是数据库使用独占式封锁机制,当执行上面的语句时,对表进行锁住,直到发生commite或者回滚或者退出数据库用户

  • 锁表的原因:

    • 第一.A程序执行了对tableA的insert,并还未commite时,B程序也对tableA进行insert,则此时会发生资源正忙的异常,也就是锁表

    • 第二.锁表常发生于并发而不是并行(并行时,一个线程操作数据库时,另一个线程是不能操作数据库的,cpu和io分配原则)

  • 减少锁表的概率:

    • 减少insert,update,delete语句执行到commite之间的时间.具体点:批量执行改为单个执行,优化sql自身的非执行速度

    • 如果异常,对事务进行回滚

MySQL大致可归纳为以下3种锁:

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

  • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

MyIsam锁表:不支持事务,不会出现死锁

  • 在使用MyIsam时,我们只可以使用表级锁,而MySQL的表级锁有两种模式:

表共享锁(Table Read Lock)和表独占写锁(Table Write Lock),他们在工作时表现如下:

  • 对某一个表的读操作,不会阻塞其他用户对同一表请求,但会阻塞对同一表的写请求;

  • 对MyISAM的写操作,则会阻塞其他用户对同一表的读和写操作;

  • MyISAM表的读操作和写操作之间,以及写操作之间是串行的。

InnoDB锁表:支持事务,会出现死锁

  • InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁

行级锁和表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题。

  • InnoDB实现了以下两种类型的行锁。

    • 共享锁(s):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。xxx lock in share mode

    • 排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。xxx for update

  • 另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。

    • 意向共享锁(IS):事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

    • 意向排他锁(IX):事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

  • 间隙锁(Next-Key锁)

    • 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB(可重复读、串行化级别下才有效)会给符合条件的已有数据的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。

    • 举例来说,假如emp表中只有101条记录,其empid的值分别是1,2,...,100,101,下面的SQL:

    • SELECT * FROM emp WHERE empid > 100 FOR UPDATE  
    • 是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁也会对empid大于101(这些记录并不存在)的“间隙”加锁

    • InnoDB使用间隙锁的目的

      • 一方面是为了防止幻读,以满足相关隔离级别的要求,对于上面的例子,要是不使用间隙锁,如果其他事务插入了empid大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读

      • 另一方面,是为了满足其恢复和复制的需要。有关其恢复和复制对机制的影响,以及不同隔离级别下InnoDB使用间隙锁的情况

  • 很显然,在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待因此,在实际开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件

  • 其次,间隙锁的存在可能会导致死锁,如下:

注意:不同session下的间隙锁之间不会冲突(间隙锁不互锁),跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作

二.用索引字段做为条件进行修改时, 是否表锁的取决于这个索引字段能否确定记录唯一,当索引值对应记录不唯一,会进行锁表,相反则行锁

例:

  • 存储过程循环30次更新操作(cycore_file_id 为唯一标识)

    • 执行结果:持续一段时间后速度越来越慢,出现等待锁

    • 原因

      MySQL的innodb存储引擎支持行级锁,innodb的行锁是通过给索引项加锁实现的,这就意味着只有通过索引条件检索数据时,innodb才使用行锁,否则使用表锁。根据当前的数据更新语句(update jx_attach set complete=1,attach_size=63100 where cycore_file_id=‘hahaha’;),该条件字段cycore_file_id并没有添加索引,所以导致数据表被锁。

    • 解决办法 为cycore_file_id添加索引

  • 假设kid是表table 的 一个索引字段 且值不唯一

    • 如果kid 有多个值为12的记录那么: update table set name=’feie’ where kid=12; 会锁表

    • 如果kid有唯一的值为1的记录那么: update table set name=’feie’ where kid=1; 不会锁

三.同一个表,如果进行删除操作时,尽量让删除条件统一,否则会相互影响造成锁表

例:

  • 如果有两个delete 而 kid1 与 kid2是索引字段

    • 语句1 delete from table where kid1=1 and kid2=2; 语句2 delete from table where kid1=1 and kid2=3; 这样的两个delete 是不会锁表的

    • 语句1 delete from table where kid1=1 and kid2=2; 语句2 delete from table where kid1=1 ; 这样的两个delete 会锁表

什么时候使用表锁

  • 对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁。

    • 第一种情况是:事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。

    • 第二种情况是:事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。

关于死锁

  • MyISAM表锁是deadlock free的,这是因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但是在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了InnoDB发生死锁是可能的。

    • 发生死锁后,InnoDB一般都能自动检测到,并使一个事务释放锁并退回,另一个事务获得锁,继续完成事务。有以下两种处理方式

      • 直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置(默认50s),对于在线服务来说,这个等待时间往往是无法接受的

      • 如果设置成1s,这样当出现死锁的时候,确实很快就可以解开,但如果不是死锁,而是简单的锁等待,则会造成很多误伤

    • (推荐)主动死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑

      • 如果出现很多事务都要更新同一行的场景(热点行),每个新来的被堵住的线程都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度是O(n)的操作。假设有1000个并发线程要同时更新同一行,那么死锁检测操作就是100万这个量级的。虽然最终检测的结果是没有死锁,但是这期间要消耗大量的CPU资源。因此,你就会看到CPU利用率很高,但是每秒却执行不了几个事务

        • 对于上述的情况,如果能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉(头痛医头)

        • 控制并发度,如过同一行同时最多只有10个线程在更新,那么死锁检测的成本很低,就不会CPU占用高的问题。这个并发控制最好是在数据库Server端 / 中间件进行,而不能在客户端,因为通常会有很多客户端/很多连接/很多线程。其思路一般是:对于相同行的更新,在进入引擎之前排队。这样在InnoDB内部就不会有大量的死锁检测工作了(不能让他进入数据库)

        • 将一行改成逻辑上的多行来减少锁冲突

    • 但在涉及外部锁,或涉及锁的情况下,InnoDB并不能完全自动检测到死锁,这需要通过设置锁等待超时参数innodb_lock_wait_timeout来解决。需要说明的是,这个参数并不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获取所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖垮数据库。我们通过设置合适的锁等待超时阈值,可以避免这种情况发生

锁表:MyISAM非聚集索引和InnoDB聚集索引的各种锁表问题相关推荐

  1. mysql myisam表加索引_MyISAM和InnoDB的索引实现

    在 MySQL 中,主要有四种类型的索引,分别为: B-Tree 索引, Hash 索引, Fulltext 索引和 R-Tree 索引.我们主要分析B-Tree 索引. B-Tree 索引是 MyS ...

  2. B+树在MySQL索引的应用和InnoDB的索引优化

    B树索引算法介绍 1.B树 B树又称为多路平衡查找树,它类似普通的平衡二叉树,不同的一点是B树允许每个节点有更多的子节点. B树有如下特点: 具有n个关键字的节点含有(n+1)棵子树 所有键值分布在整 ...

  3. mysql索引数据结构图解_MySQL索引底层结构与实现原理

    为什么要使用索引 MySQL官方定义为:索引(Index)是帮助 MySQL 高效获取数据的数据结构,类似于书的目录结构一样. 如果向mysql发出一条sql语句请求,查询的字段没有创建索引的话,可能 ...

  4. MySQL索引底层实现原理 MyISAM非聚簇索引 vs. InnoDB聚簇索引

    MySQL索引底层实现原理 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的 ...

  5. 【MySQL索引】底层实现原理 MyISAM非聚簇索引 vs. InnoDB聚簇索引

    MySQL索引底层实现原理 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的 ...

  6. 德鲁伊 oltp oltp_深入研究内存中OLTP表的非聚集索引

    德鲁伊 oltp oltp With the introduction of Microsoft's new In-Memory OLTP engine* (code name Hekaton) a ...

  7. mysql的表是聚集索引组织表_Mysql的Innodb引擎索引总结

    索引的目的是什么? 答:数据库添加索引的目的是为了加快查询速度. 索引的的数据结构是什么? 答:(这里的B是balance)B+树来存储索引,B+树类似于二叉树. B+树是怎么查找数据的? 答:B+树 ...

  8. MyISAM与InnoDB的索引实现

    1.MyISAM 使用B+Tree 作为索引结构,叶子节点的data存放指针,也就是记录的地址.对于主键索引和辅助索引都是一样的. 2.InnoDB 也使用B+Tree作为索引结构,也别需要注意的是, ...

  9. 主码索引、聚集索引、非主码索引(辅助索引)、唯一索引、外键索引、复合索引、非主码索引、聚集主码(聚集索引)、单列索引、多列索引、普通索引等...

    强烈建议看了第一个参考文献再来看这个篇博文,因为此处不准备讲底层数据结构的实现. 索引:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构.其 ...

最新文章

  1. python操作系统-PYTHON-操作系统基础
  2. if you are alone with your mac connected to Internet
  3. Bigtable的些许重点
  4. http://w3cschool.codecloud.net/python/python-object.html?ref=myread
  5. php门面理解,php 门面模式(外观模式)
  6. JMeter二次开发(1)-eclipse环境配置及源码编译
  7. property练习
  8. java委_java双亲委派机制及作用
  9. 汉字转拼音以及五笔码
  10. .gen格式文件读取,完成兰伯特和墨卡托投影转换
  11. c语言编程 设计密码锁,单片机控制安全密码锁的设计(附程序,pcb,原理图)
  12. 【网易互娱模拟笔试】解题记录
  13. Perl-LWP文档
  14. Mac升级Catalina,根目录下无法创建个人文件夹
  15. 电商52个专业名词解释大汇总
  16. 基于VGG19的识别中国人、韩国人、日本人分类器
  17. 初试-基于神经网络的植物识别
  18. 计算机状态oxcoooooe9,电脑蓝屏后开机显示状态Oxcoooooe9
  19. 深度神经网络(DNN)Deep Neural Networks 介绍
  20. k8s集群部署中etcd启动报错request sent was ignored (cluster ID mismatch: peer[c39bdec535db1fd5]=cdf818194e3a8c

热门文章

  1. python学习——python实现冒泡排序算法
  2. 寻找一个不用彷徨的街头
  3. matlab 对图像进行低通滤波,matlab图像处理实现低通滤波
  4. 三 通用目标之make vmlinux的执行过程分析
  5. sobel算子原理与实现
  6. 签到界面加图片java_(三)开始在OJ上添加签到功能
  7. 分析的六种中小企业网络营销方法
  8. 飞链云版图的魔咒教室(1)AI绘画新手教程
  9. Froala Editor内容中删除内联样式
  10. SQL Server 2014 更新数据(添加数据、修改数据、删除数据、like)