前言

前言为本人写这篇文章的牢骚,建议跳过不看。

  之前好几次都想好好的学习MySQL中的锁,但是找了几篇文章,看了一些锁的类型有那么多种,一时间也没看懂是什么意思,于是跟自己说先放松下自己,便从书桌起来在阳台发呆、做做运动、打扫下公寓,时间就这样过去了,真就印证了那句话:"当你在学习的时候,无论做什么其他的事情都是有趣的。"但却又能安慰自己:"我不是不想学习,只是在学习的过程中放松了下自己,下次再看吧吧",这样心里也不会存有罪恶感,安稳睡去,下次亦是重复如此。但是日志一长,MySQL锁就变成了一块又硬又重的石头,完全不想碰它。但是这几天重新看了一遍,发现这块石头减肥了,于是便有了这篇文章。

MySQL的锁

  首先在阅读文章之前,得先理解一个概念:锁之间的互斥是作用于获取锁来说的。举个例子,我拿到了一条记录的X锁,如果其他线程想要获取这条记录的其他锁,那么就需要等待,这就是互斥;但是如果其他线程不想获取锁,只是简单的访问,例如说select * from t where id = 1这些不用锁的语句,并不需要获取此记录的锁,那么这个SQL不会进入阻塞,并不会形成互斥。

共享锁/独占锁(Shared and Exclusive Locks)

  一种比较大的分类,不一定指行锁,也可能是表锁。如果是X锁(独占锁)则跟其他所有锁形成互斥;如果是S锁(共享锁),则可实现读读(SS)并行。哈?你叫我举个例子。okay,拿行锁(记录锁)来说,当我们执行下面的SQL时当前事务拿到的是id为3的X行锁。

update t set name = 'name1' where id = 3;

  那么代表什么呢,代表如果上方的事务还没结束的话,此时下面的操作都会被阻塞。

// 获取记录上的S锁
select * from t where id = 3 lock in share mode;
// 获取记录上的X锁
update t set name = 'name2' where id = 3;

  也就是说,共享锁和独占锁的互斥关系如下表。

X S
X 互斥 互斥
S 互斥 兼容

  但是,这个时候我有一个问题。

  如果执行的这个语句呢?

select * from t where id = 3;

  是否还会出现阻塞的情况呢?好好的思考一下,然后想想自己为什么要想这个没有意义的问题。

  答案是不会出现阻塞的情况,原因我在一开始的时候就说了,互斥是针对锁的争夺来说的,上面的这条SQL并不需要获取到锁,所以也就不会进入阻塞。

意向锁(Intention Locks)

  在讲意向锁之前,我们首先思考这样的一个问题:

  如果我想对整张表进行独占式锁定(即X表锁),我没办法像个莽夫一样直接就锁上了,我得知道表中的记录有没有被其他的事务锁住,如果有的话那么我就进入阻塞等待释放,那要怎么知道呢?

  暴力点从第一条记录开始遍历到最后?不行,如果一张表有几百万甚至上千万的话效率就会非常低下(别跟我说该分表了)。于是,为了解决这种性能问题,意向锁应援而生。

  意向锁就是为了提升获取表锁前判断而存在的锁。首先意向锁是表级别锁(表锁跟行锁是可以同时存在不冲突),在获取数据行上的独占锁或者共享锁之前首先得获取到表级别的意向锁,这样子,当有其他线程想要进行锁表的时候,看到已经存在意向锁,那么就进入阻塞状态,而不用遍历所有数据行判断是否行上有锁,这样子就大幅提升了性能。

  意向锁也分共享意向锁(IS)和独占意向锁(IX)。意思也很简单,获取S锁之前需要获取的就是IS锁,获取X锁之前需要获取的就是IX锁,其锁之间的互斥关系如下图。

X S
IX 互斥 互斥
IS 互斥 兼容

  看了上面的图,可能有人会问:"兄弟,你这只有跟独占/共享锁的互斥图,意向锁之间的互斥关系呢?"

  首先,我得跟你说,我绝对不是因为懒得画图才不画的,因为意向锁之间是不互斥的。你想嘛,本来意向锁就是为了提升锁表时的判断性能而存在的,而且本身自己也是表级别的锁,你还给整个互斥关系,到时候不给你堵得像北京三环一样,所以不互斥是一级棒的。

记录锁(Record Locks)

  在上方也简单的提到过记录锁,记录锁也称行锁,是一种针对特定索引上的锁,注意是索引,而且如果只有记录锁的话必须是唯一索引(意思就是说只有记录锁一种,而非临建锁),过程为通过唯一索引定位到对应的聚簇索引,然后将这条聚簇索引锁住。如果唯一索引是多列组成的,但是查询条件只用到了其中几列,这种情况就不是施加记录锁,比方说,唯一索引为uniq_index(name,age),但是条件为where name = 'name1',这个时候用到的就不是记录锁而是临建锁了。

间隙锁(Gap Locks)

  对于一些非唯一索引的查询或者范围查询的情况下,使用到的就是间隙锁。怎么理解呢,来看下官方给出的文档:

A gap lock is a lock on a gap between index records, or a lock on the gap before the first or after the last index record.

  意思就是说间隙锁是在索引之间、第一个索引之前或者最后一个索引之后的锁。这样讲可能还是有点抽象,举个简单的例子,假设现在有这样的一张表:

id(bigint) name(varchar)
3 n3
5 n5
7 n7

  再结合上面那句话的意思,那么可以知道这张表中间隙锁的取值范围为

(负无穷,3),

(3,5),

(5,7),

(7, 正无穷)

  有些文章的范围会将右边边界也取上,但我觉得这样反而不符合官方文档的定义,而且不好理解,不过取上也没关系,因为间隙锁一般不会单独使用,一般使用的都是临键锁(临键锁的话会把记录带上,也就是边界也取到了),所以锁的范围都是一样的,看个人觉得哪个容易理解。另外关于间隙锁的范围,官方描述中有一段有趣的描述,是这样的:

​ A gap might span a single index value, multiple index values, or even be empty.

  意思就是说,间隙可以是一个索引、可以跨越多个索引,甚至可以是空的;换句话说,"根本就没有间隙锁,或者说,哪里都是间隙锁。"

  另外需要注意:间隙锁只有在RC级别及以上的隔离级别中才有,其他级别是没有间隙锁的。

  讲了这么多可能还是云里雾里的,来举个简单的例子,还是上面表格中的记录。

id(bigint) name(varchar)
3 n3
5 n5
7 n7

  id的值分别为3、5、7,那么下面这条SQL的间隙范围是多少呢?

select * from t where id between 3 and 5 for update;

  你以为是(3,5)?其实是(3,5)和(5,7)哒,这也另一方面证实了官方说的间隙锁可能跨越索引的说法。实际上由于临键锁的存在,会把记录锁也带上,也就是边界3、5、7都会被锁住(即范围为[3,7],已验证,若有其他见解请在评论区狠狠的打我的脸,不要客气,打得越狠越好)。

  讲到这里,可能有人会说,”你说的这些我现在懂了,那这个间隙锁到底有什么用呢?"

  emmm,先看下官方文档是怎么说的:

  Gap locks in InnoDB are “purely inhibitive”, which means that their only purpose is to prevent other transactions from inserting to the gap.

  用我的工地英语翻译过来就是,间隙锁不会阻塞,唯一的作用就是防止其他事务往这个间隙中插入记录;毫不客气的说,间隙锁除了防止在间隙之间插入记录之外一无是处,间隙锁之间甚至还可以共存(无论是X还是S间隙锁),你锁(3,5)跟我锁(2,6)又有什么关系呢?

临键锁(next-key locks)

  上方介绍间隙锁的时候多多少少也提到过,临键锁就是记录锁+间隙锁的结合。一般来说使用的都是临键锁而非间隙锁,上方的SQL:

select * from t where id between 3 and 5 for update;

 锁定的范围带上边界也说明了,实际上边界上的锁都是记录锁,所以范围才变成了[3, 7]。当然使用的是唯一索引的话会进化成记录锁(多列索引的情况需另外考虑,记录锁处已提到),下面这个SQL用的就是记录锁。

select * from t where id = 3 for update;

插入意向锁

  一种特殊的间隙锁,在其间隙中可以进行非当前记录的插入,目的是为了提高插入的并发,可以理解为间隙为1的间隙锁。 同时也是一种意向锁,只不过这是给插入专用的。

自增锁

  表锁,一般用在设置了auto_increment的字段。大致就是先获取锁,然后将最大的ID自增,与其他锁不同的时候,完成自增操作之后其就释放了,不需要等待事务的完成。

  

本文为博客园原创文章,文章地址

参考:

https://blog.csdn.net/qq_41026740/article/details/97408858

https://zhuanlan.zhihu.com/p/48269420

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-insert-intention-locks

MySQL锁这块石头似乎没有我想的那么重的更多相关文章

  1. mysql锁

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

  2. mysql锁表机制及相关优化

    (该文章为方便自己查阅,也希望对大家有所帮助,转载于互联网) 1. 锁机制 当前MySQL支持 ISAM, MyISAM, MEMORY (HEAP) 类型表的表级锁,BDB 表支持页级锁,InnoD ...

  3. Mysql锁机制--并发事务带来的更新丢失问题

    Mysql 系列文章主页 =============== 刚开始学习 Mysql 锁的时候,觉得 Mysql 使用的是行锁,再加上其默认的可重复读的隔离级别,那就应该能够自动解决并发事务更新的问题.可 ...

  4. Mysql锁机制--索引失效导致行锁变表锁

    Mysql 系列文章主页 =============== Tips:在阅读本文前,最好先阅读 这篇(Mysql锁机制--行锁)文章~ 在上篇文章中,我们看到InnoDB默认的行锁可以使得操作不同行时不 ...

  5. Mysql 锁和锁算法

    相关命令: show engines;  查看数据库支持的引擎 show variables like '%storage_engine%';   查看数据库默认的引擎 select @@global ...

  6. MySQL锁解决并发问题详解

    文章分为以下几个要点 问题描述以及解决过程 MySQL锁机制 数据库加锁分析 下面讨论的都是基于MySQL的InnoDB. 0. 问题描述以及解决过程 因为涉及到公司利益问题,所以下面很多代码和数据库 ...

  7. 深入理解 MySQL ——锁、事务与并发控制

    本文首发于vivo互联网技术微信公众号 mp.weixin.qq.com/s/JFSDqI5ya… 作者:张硕 本文对 MySQL 数据库中有关锁.事务及并发控制的知识及其原理做了系统化的介绍和总结, ...

  8. MYSQL锁表问题解决

    本文实例讲述了MYSQL锁表问题的解决方法.分享给大家供大家参考,具体如下: 很多时候!一不小心就锁表!这里讲解决锁表终极方法! 案例一 ? 1 mysql>show processlist; ...

  9. MySQL锁(行锁、表锁、页锁、乐观锁、悲观锁等)

    锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具.在计算机中,是协调多个进程或县城并发访问某一资源的一种机制.在数据库当中,除了传统的计算资源(CPU.RAM.I/O等等)的争用之外,数据也是一 ...

随机推荐

  1. x86架构: 硬件启动过程分析(附引导启动代码)

    用户按下开机键,几秒的时间,都经历了啥? 1.cpu各个寄存器赋初始值,cs.base=0xffff0000, eip=0xfff0,其他寄存器都是0,这时cs:ip得到的物理地址:0xfffffff ...

  2. MR程序的几种提交运行模式

    本地模式运行 1-在windows的eclipse里面直接运行main方法 将会将job提交给本地执行器localjobrunner 输入输出数据可以放在本地路径下 输入输出数据放在HDFS中:(hd ...

  3. Rest接口加Https单向认证

    背景: 接到一个需求,客户要求某个模块的rest接口都得通过https访问,客户提供证书. 步骤: Server端证书生成 刚开始还没拿到客户的证书,所以通过jdk自带的keytools自己先生成了一 ...

  4. 银弹谷V百科|使用技巧:Vbase技巧二则之一

    银弹谷零代码开发V平台提供访问窗体的短地址链接 格式:http://IP:port/form/componentCode/windowCode  例子: 默认地址:http://IP:port/mod ...

  5. Python嫌多(线程/进程)太慢? 嫌Scrapy太麻烦?没事,异步高调走起!——瓜子二手车

    基本概念了解: 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那么针对这三类人,我 ...

  6. 谈谈集成测试(integration testing)

    对于软件开发来说,软件测试是一个几乎贯穿所有阶段的活动,所以测试的重要性毋庸置疑.不同开发组织如何在不同的产品研发阶段进行测试,也在很大程度上反映了其研发能力和质量控制能力.软件测试有很多类型,包括单 ...

  7. 03-java实现循环链表

    03java实现循环链表 本人git https://github.com/bigeyes-debug/Algorithm 一丶单向循环链表 就是为尾节点指向头结点 二丶单向循环链表的接口设计 比较单 ...

  8. 详解 LSTM

    LSTM 长短时记忆网络(Long Short Term Memory Network, LSTM),是一种改进之后的循环神经网络,可以解决RNN无法处理长距离的依赖的问题,目前比较流行. 长短时记忆 ...

  9. 苹果TF上架的iOS应用怎么下载

    苹果TF上架的iOS应用怎么下载 苹果TF上架的iOS应用是无法通过App Store搜索到的,需要用户先从App Store中搜索下载testflight内测商店.当开发者进行苹果TF上架成功以后会 ...

  10. CodeReview 的经验和原则

    资深的程序员都知道 Code Review 可以对代码质量,代码规范,团队代码能力提升带来很大的提升,还有著名的技术专家"左耳朵耗子"也说过: 我认为没有 Code Review ...