首页 > 数据库 >(转载)Mysql里的锁(排它锁、共享锁、行锁、表锁、间隙锁、临键锁、意向锁)

(转载)Mysql里的锁(排它锁、共享锁、行锁、表锁、间隙锁、临键锁、意向锁)

时间:2023-06-28 11:47:06浏览次数:55  
标签:事务 加锁 行锁 锁住 临键 索引 Mysql 共享

转载自:Mysql里的锁(排它锁、共享锁、行锁、表锁、间隙锁、临键锁、意向锁)

一、加锁的目的是什么?

在我们了解数据库锁之前,首先我们必须要明白加锁的目的是为了解决什么问题,如果你还不清楚的话,那么从现在起你应该知道,数据库的锁是为了解决事务的隔离性问题,为了让事务之间相互不影响,每个事务进行操作的时候都会对数据加上一把特有的锁,防止其他事务同时操作数据。如果你想一个人静一静,不被别人打扰,那么请在你的房门上加上一把锁。

 


 

二、锁实是基于什么实现的?

为了后面大家后面对锁理解的更透彻,所以务必要对此进行说明,锁是基于什么实现的,你现实生活中家里的锁是基于门来实现的,那么数据库的锁又是基于什么实现的呢? 那么我在这里可以告诉你,数据库里面的锁是基于索引实现的,在Innodb中我们的锁都是作用在索引上面的,当我们的SQL命中索引时,那么锁住的就是命中条件内的索引节点(行锁),如果没有命中索引的话,那我们锁的就是整个索引树(表锁),如下图一下锁住的是整棵树还是某几个节点,完全取决于你的条件是否有命中到对应的索引节点。

innodb索引结构图(B+ tree):

 


 

三、锁的分类。

数据库里有的锁有很多种,为了方面理解,所以我根据其相关性"人为"的对锁进行了一个分类,分别如下

基于锁的属性分类:共享锁、排他锁。

基于锁的粒度分类:表锁、行锁、记录锁、间隙锁、临键锁。

基于锁的状态分类:意向共享锁、意向排它锁。

 

1、属性锁

 

共享锁(Share Lock)

共享锁又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。

 

共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。

 

排他锁(eXclusive Lock)

排他锁又称写锁,简称X锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。

 

排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取。避免了出现脏数据和脏读的问题。

 

2、粒度锁

表锁

表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问;

特点: 粒度大,加锁简单,容易冲突;

 

行锁

行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问;

特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高;

 

记录锁(Record Lock)

记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录。

 

触发条件:精准条件命中,并且命中的条件字段是唯一索引;

例如:update user_info set name=’张三’ where id=1 ,这里的id是唯一索引。

记录锁的作用:加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题。

 

间隙锁(Gap Lock)

间隙锁属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。

比如下面的表里面的数据ID 为 1,4,5,7,10 ,那么会形成以下几个间隙区间,-n-1区间,1-4区间,7-10区间,10-n区间 (-n代表负无穷大,n代表正无穷大)

 

触发条件:范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中。

例如:对应上图的表执行select * from user_info where id>1 and id<4 for update(这里的id是唯一索引) ,这个SQL查询不到对应的记录,那么此时会使用间隙锁。

间隙锁作用:防止幻读问题,事务并发的时候,如果没有间隙锁,就会发生如下图的问题,在同一个事务里,A事务的两次查询出的结果会不一样。

 

临键锁(Next-Key Lock)

临键锁也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住。

例如:下面表的数据执行 select * from user_info where id>1 and id<=13 for update ;

会锁住ID为 1,5,10的记录;同时会锁住,1至5,5至10,10至15的区间。

 

触发条件:范围查询并命中,查询命中了索引。

临键锁的作用:结合记录锁和间隙锁的特性,临键锁避免了在范围查询时出现脏读、重复读、幻读问题。加了临键锁之后,在范围区间内数据不允许被修改和插入。

 

3、状态锁

状态锁包括意向共享锁和意向排它锁,把他们区分为状态锁的一个核心逻辑,是因为这两个锁都是都是描述是否可以对某一个表进行加表锁的状态。

意向锁的解释:当一个事务试图对整个表进行加锁(共享锁或排它锁)之前,首先需要获得对应类型的意向锁(意向共享锁或意向共享锁)

意向共享锁

当一个事务试图对整个表进行加共享锁之前,首先需要获得这个表的意向共享锁。

意向排他锁

当一个事务试图对整个表进行加排它锁之前,首先需要获得这个表的意向排它锁。

 

为什么我们需要意向锁?

意向锁光从概念上可能有点难理解,所以我们有必要从一个案例来分析其作用,这里首先我们先要有一个概念那就是innodb加锁的方式是基于索引,并且加锁粒度是行锁,然后我们来看下面的案例。

 

第一步:

事务A对user_info表执行一个SQL:update user_info set name =”张三” where id=6 加锁情况如下图;

 

第二步:

与此同时数据库又接收到事务B修改数据的请求:SQL: update user_info set name =”李四”;

1、因为事务B是对整个表进行修改操作,那么此SQL是需要对整个表进行加排它锁的(update加锁类型为排他锁);

2、我们首先做的第一件事是先检查这个表有没有被别的事务锁住,只要有事务对表里的任何一行数据加了共享锁或排他锁我们就无法对整个表加锁(排他锁不能与任何属性的锁兼容

3、因为INNODB锁的机制是基于行锁,那么这个时候我们会对整个索引每个节点一个个检查,我们需要检查每个节点是否被别的事务加了共享锁或排它锁。

4、最后检查到索引ID为6的节点被事务A锁住了,最后导致事务B只能等待事务A锁的释放才能进行加锁操作。

 

思考:

在A事务的操作过程中,后面的每个需要对user_info加持表锁的事务都需要遍历整个索引树才能知道自己是否能够进行加锁,这种方式是不是太浪费时间和损耗数据库性能了?

所以就有了意向锁的概念:如果当事务A加锁成功之后就设置一个状态告诉后面的人,已经有人对表里的行加了一个排他锁了,你们不能对整个表加共享锁或排它锁了,那么后面需要对整个表加锁的人只需要获取这个状态就知道自己是不是可以对表加锁,避免了对整个索引树的每个节点扫描是否加锁,而这个状态就是我们的意向锁

 

标签:事务,加锁,行锁,锁住,临键,索引,Mysql,共享
From: https://www.cnblogs.com/r1-12king/p/17510973.html

相关文章

  • G1垃圾回收参数调优及MySQL虚引用造成GC时间过长分析 | 京东云技术团队
    1.背景我方有一应用,偶尔会出现GC时间过长(间隔约4小时),导致性能波动的问题(接口最长需要耗时3秒以上)。经排查为G1垃圾回收器参数配置不当叠加MySQL链接超过闲置时间回收,产生大量的虚引用,导致G1在执行老年代混合GC,标记阶段耗时过长导致。以下为对此问题的分析及问题总结。此外,此......
  • mysql系列基础篇01---通用的语法及分类
    通用语法及分类DDL:数据定义语言,用来定义数据库对象(数据库、表、字段)DML:数据操作语言,用来对数据库表中的数据进行增删改DQL:数据查询语言,用来查询数据库中表的记录DCL:数据控制语言,用来创建数据库用户、控制数据库的控制权限一、DDL(数据定义语言)1、数据库操作1.1创......
  • 如何解析和读取mysql binlog
    要解析和读取MySQL的二进制日志(binlog),可以使用一些工具和方法。MySQL官方提供的工具:MySQL自带了一个名为mysqlbinlog的命令行工具,可以用于解析和读取二进制日志。通过执行以下命令,您可以查看二进制日志的内容:mysqlbinlog[options][binlog_files]options是......
  • C++ - 连接mysql数据库
    1.准备工作1.1把libmysql.dll和libmysql.lib文件复制到工程目录下首先,我们要找到刚刚开始下载的MySQL数据库的安装目录,打开目录,并且将libmysql.dll文件和libmysql.lib文件复制到工程目录下~我安装MySQL的路径:C:\ProgramFiles\MySQL\MySQLServer5.7\lib 1.2......
  • 解决:远程连接mysql:报异常,1044 - Access denied for user ‘root‘@‘%‘ to database
    Navicat报错:使用Navicat远程连接,Docker中的mysql5.6时报异常,:1044-Accessdeniedforuser'root'@'%'todatabase'xxx'问题原因:(1)根本原因:远程连接用户权限不足!(2)直接原因:应该是创建远程连接用户‘root@%’时,没有添加访问数据库的权限。解决办法:#这里为刚才创建的root@......
  • 一文总结高并发大数据量下MySQL开发规范【军规】
    在互联网公司中,MySQL是使用最多的数据库,那么在并发量大、数据量大的互联网业务中,如果高效的使用MySQL才能保证服务的稳定呢?根据本人多年运维管理经验的总结,梳理了一些基础的开发规范,希望能给大家带来一些帮助。一、基础规范数据库字符集默认使用utf8mb4,兼容utf8,并支持存储emoji......
  • #yyds干货盘点#线上MySQL的自增id用尽处理
    MySQL的自增id都定义了初始值,然后不断加步长。虽然自然数没有上限,但定义了表示这个数的字节长度,计算机存储就有上限。比如,无符号整型(unsignedint)是4个字节,上限就是2^32-1。那自增id用完,会怎么样?表定义自增值id表定义的自增值达到上限后的逻辑是:再申请下一个id时,得到的值保持不......
  • mysql常用命令
    连接到MySQL服务器:mysql-uusername-p显示数据库列表:SHOWDATABASES;创建数据库:CREATEDATABASEdatabase_name;删除数据库 USEdatabase_name;DROPDATABASEdatabase_name;  切换到指定数据库:USEdatabase_n......
  • mysql MHA
    一:主从复制作用和缺点2.MHA的作用特点3.MHA节点的类型 本文用到的软件包在以下链接中https://pan.baidu.com/s/11ikNZ5sJcXRJA3sRMfUfaA?pwd=lomn使用的系统版本为centos7.4版本,mysql版本为8.0.32,本文使用四台centos7.4虚拟机安装mysql不再赘述,可翻阅博主以前的博客二:创建主从复制......
  • MySQL安装与卸载
    MySQL安装下载地址官网下载地址:https://dev.mysql.com/downloads/mysql/解压安装包将安装包解压(尽量解压在没有空格没有中文的目录下)##配置MySQL此电脑->属性->高级系统设置->环境变量在系统环境变量中新建变量名为:MYSQL_HOME的变量,变量值为MySQL的解压目录在......