前言

  换了工作之后,接近半年没有发博客了(一直加班),emmmm.....今天好不容易有时间,记录下工作中遇到的一些问题,接下来应该重拾知识点了。因为新公司工作中MySQL库经常出现查询慢,锁等待,节点挂掉........等一系列问题。导致每个程序员头都很大,一味抱怨“为什么我就查一条数据这么卡”,"我TM加了索引的啊,怎么还怎么慢"...........我想默默说的是,大部分MySQL出现锁等待,查询奇慢的情况基本都是因为SQL写的不好(有坑),或者数据表设计的不完善。对,不用想!这些所有的坑很大一部分都是自己造成的。那么是什么原因造成的,大部分只是抱怨,而不去关注MySQL的一些细节问题,比如:MySQL行锁的细节,什么情况下会使用表锁等。所以今天先讨论记录下InnoDB特有的行锁的一些细节,加强认识。

  InnoDB不同于MyISAM最大的两个特点就是:一是支持事务,二是支持行锁;毋庸置疑,因为这两个特性大部分都采用InnoDB引擎,其中的支持行锁就是InnoDB适合多并发优势所在,但是行锁的一些细节没有深入理解过的话,可能会造成一定的误解,造成“看似命中索引,走行锁,结果却是表锁,最终导致锁等待情况”。


一、InnoDB行锁的实现方式

  通过给索引上的索引项加锁来实现的,也就意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。这一点在实际应用中特别需要注意,不然的话可能导致大量的锁冲突,从而影响引发并发性能

  实验一:对没有索引的加锁,导致表锁

   1)准备工作:建tab_no_index表,表中无任何索引,并插入数据

    

   2)Session_1: 我们给id=1的行加上排它锁(for update),由于id没有索引,实际上是表级锁;

    

   3)Session_2:我们给id=2的行加上排它锁(for update),由于id没有索引,所以去申请表级锁,但是却出现了锁等待!原因就是在没有索引的情况下,InnoDB只能使用表锁。

   

    备注:MySQL中的for update 仅适用于InnoDB(因为是只有此引擎才有行级锁),并且必须开启事务,在begin与commit之间才生效。for update是在数据库中上锁用的,可以为数据库中的行上一个排它锁。当一个事务的操作未完成时候,其他事务可以对这行读取但是不能写入或更新,只能等该事务Rollback, Commit, Lost connection…

   实验二:对有索引的键值加锁,会对所有涉及到的数据行加锁

    1)准备工作:对id建索引如下

    

   2)Session_1:此时id是有索引的,我们对id=1 and name=1的一行加排它锁;

    

    3)Session_2:访问不同于Session_1的id=1, name=5行,但是索引键值是一样的,照样等待锁,锁冲突了。

    

   实验三:多个索引时,不同的事务可以使用不同的索引锁定不同的行,不论什么索引,InnoDB都会使用行锁对数据加锁(对有索引的行数据)

    1)准备工作:对tab_no_index追加name索引:alter table tab_no_index add index name(name);

    

    2)Session_1:开启事务对id=1的行加排它锁,即对name=1与name=5两个数据加锁。

    

    3)Session_2:开启事务对name=2行加锁,因为该数据没有被加锁,索引可以获得锁

    

    4)Session_3:再对name=5的数据进行加锁,由于该数据记录已被Session_1锁定,所以等待获得锁。

   

  注意事项:即便使用了索引,但还是要看MySQL具体对SQL的执行计划,不一定能使用到

    如我们对实验三对name='2'进行加锁,误以为name是int类型,本来name是有索引的,但是最后结果导致表锁:

    

  

  具体请看MySQL的索引情况。具体可以参考之前我的一篇博文MySQL优化(1)--------常用的优化步骤MySQL优化(2)--------常用优化

二、间隙锁(Next-Key锁)

  当用范围条件而不是相等条件检索数据,并请求共享或者排它锁的时候,InnoDB会给符合条件的已有数据记录的索引项加锁;对于不在范围内的但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个间隙加锁,这就是所谓的间隙锁

  如:select * from where id>100 for update 对id大于100的数据对加锁,但是此时数据中id只有1,2….100,101,不仅对存在的101的记录加锁,还会对大于101不存在的数据的间隙加锁。

   此外,对使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁,如下:

  Session_1:对不存在的id=6的记录加锁

  

  Session_2:插入id=6的记录,也会出现锁等待

  

三、什么时候使用表锁?

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

  1)事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间等待和锁冲突;

  2)事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。

使用表锁需要注意几点:

  1)使用LOCK TABLES虽然可以给InnoDB加表级锁,表级锁不是InnoDB存储引擎层管理的,而是由其上一层MySQL Server负责的

  2)在用LOCK TABLES对InnoDB表加锁时需要注意,要将Autocommit设置为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCK TABLES释放表锁,因为UNLOCK_TABLES隐含提交事务;COMMIT或ROLLBACK并不能释放用LOCK TABLES加表级锁。

   SET AUTOCOMMIT=0;

   LOCK TABLES table1 WRITE, table2 READ,...;

   [do something....]

   COMMIT;

   UNLOCK TABLES;


总结:

  • 从设计之初,就应该建立良好的索引机制,避免对关键字段搜索时造成表锁;

  • 避免长时间事务未提交等情况,导致锁冲突,死锁等情况;

  • 不要老是抱怨数据库有问题,应该从自身写的SQL分析出发,学会分析(数据库不行大部分是因为SQL写的有问题,没错,是自身问题);

  • 不要总是觉得这是DBA该做的事,开发者应该学会基本的SQL常识(如MySQL的最左索引,回表,索引覆盖等知识),学会基本的优化步骤。

主要参考资料:《深入浅出MySQL》(有需要PDF电子书的伙伴可以评论或者私信我)

https://www.cnblogs.com/jian0110/p/12721924.html 

MySQL锁:InnoDB行锁需要避免的坑的更多相关文章

  1. MySQL锁---InnoDB行锁需要注意的细节

    前言 换了工作之后,接近半年没有发博客了(一直加班),emmmm.....今天好不容易有时间,记录下工作中遇到的一些问题,接下来应该重拾知识点了.因为新公司工作中MySQL库经常出现查询慢,锁等待,节 ...

  2. MySQL锁:03.InnoDB行锁

    目录 InnoDB 行锁 锁排查可以用的视图和数据字典 InnoDB 行锁兼容性 InnoDB行锁之共享锁 共享锁: 查看InnoDB锁 InnoDB行锁实现机制 对普通索引上锁 InnoDB隐式.显 ...

  3. Mysql InnoDB行锁实现方式(转)

    Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...

  4. Mysql InnoDB行锁实现方式

    Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...

  5. Mysql研磨之InnoDB行锁模式

    事务并发带来的一些问题 (1)更新丢失(LostUpdate):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题最后的更新覆盖了由其 ...

  6. mysql:InnoDB行/表级锁实现/事务

    转载:http://book.51cto.com/art/200803/68127.htm 20.3.4 InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL ...

  7. mysql的innodb 引擎 表锁与行锁

    innodb 引擎 行锁与表锁 行锁与表锁是基于索引来说的(且索引要生效) 不带索引 (表锁)要全表扫描 1. 执行select @@autocommit; 查看结果 0是不自动提交事务,1是自动提交 ...

  8. mysql 开发进阶篇系列 9 锁问题 (Innodb 行锁实现方式)

    一.概述 Innodb 行锁是通过给索引上的索引项加锁来实现的.这一点与(oracle,sql server)不同后者是通过在数据块中对相应的数据行加锁.这意味着只有通过索引条件检索数据,innodb ...

  9. Innodb行锁源码学习(一)

    Innodb是mysql数据库中目前最流行的存储引擎,innodb相对其它存储引擎一个很大的特点是支持事务,并且支持行粒度的锁.今天我重点跟大家分享下innodb行锁实现的基础知识.由于篇幅比较大,文 ...

  10. MySQL中的锁(表锁、行锁)

    锁是计算机协调多个进程或纯线程并发访问某一资源的机制.在数据库中,除传统的计算资源(CPU.RAM.I/O)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所在有数 ...

随机推荐

  1. 给C#新增一个时间类型: YearMonth

    在.Net Framework中,我们常用的时间类型是DateTime.直到.Net6微软加入了两个新的时间类型:DateOnly和TimeOnly,才弥补了之前的不足. DateOnly:表示仅日期 ...

  2. [爬虫]1.2.2 CSS选择器

    CSS (Cascading Style Sheets) 是一种样式表语言,用于描述HTML元素的样式.CSS选择器是CSS规则的一部分,它决定了CSS规则应用于哪些元素.在网络爬虫的开发中,我们经常 ...

  3. python: 获取整个字段转换成列表,并将列表转换成字典

    获取整个字段转换成列表,并将列表转换成字典

  4. 基于md5加密的模拟管理员登录系统

    import os import pandas as pd def md5(string:str=''):     import hashlib     md5 = hashlib.md5()     ...

  5. 遥遥领先 spring,中国人的 solon 来啦!10% 的体积,10倍的速度

    Solon 是什么? Java 生态型应用开发框架.它从零开始构建,有自己的标准规范与开放生态(历时五年,已有全球第二级别的生态规模).与其他框架相比,它解决了两个重要的痛点:启动慢,费内存.2023 ...

  6. 文心一言 VS 讯飞星火 VS chatgpt (75)-- 算法导论7.2 4题

    四.如果用go语言,银行一般会按照交易时间来记录某一账户的交易情况.但是,很多人却喜欢收到的银行对账单是按照支票号码的顺序来排列的.这是因为,人们通常都是按照支票号码的顺序来开出支票的,而商人也通常都 ...

  7. Docker下elasticsearch8部署、扩容、基本操作实战(含kibana)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇记录了用docker搭建ElasticS ...

  8. [ABC140F] Many Slimes

    2023-02-13 题目 题目传送门 翻译 翻译 难度&重要性(1~10):6 题目来源 AtCoder 题目算法 贪心 解题思路 用了两个 multiset a 和一个 set s,一个 ...

  9. 安装iTerm2和oh-my-zsh

    安装iTerm2和oh-my-zsh 此文是在参考许多教程(见目录:参考)并结合本人安装经历写下的一篇关于iTerm2和oh-my-zsh的认识和超级详细安装教程.全文所有图片均为本人截屏拍摄.希望能 ...

  10. 《Web安全基础》01. 基础知识

    @ 目录 1:概念名词 1.1:域名 1.2:DNS 1.3:网站开发语言 1.4:后门 1.5:Web 1.6:Web 相关安全漏洞 2:数据包 2.1:HTTP 2.2:HTTPS 2.3:请求数 ...