【MySQL】InnoDB存储引擎中的锁

news/2024/10/19 22:21:04/

实现事务隔离级别的过程中用到了锁,所谓锁就是在事务A修改某些数据时,对这些数据加一把锁,防止其他事务同时对这些数据执行修改操作;当事务A完成修改操作后,释放当前持有的锁,以便其他事务再次上锁执行对应的操作。不同存储引擎中的锁功能并不相同,这里重点介绍 InnoDB存储引擎中的锁


1. 锁信息

锁的信息包括锁的请求(申请),锁的持有以及阻塞状态等等,都保存在 performance_schema 库的 data_locks 表中,可以通过以下方式查看:

SELECT * FROM performance_schema.data_locks\G

 当没有开启任何事务的时候查看是没有任何信息的:

 这里我是用简单的user表来进行测试展示:

 1. 开启事务并执行锁定操作

START TRANSACTION;

执行一些操作来创建锁,例如查询或修改数据,而不提交事务,这将触发锁。

select * from users where id = 1 for update;

 2. 在另一个会话中查看锁信息

*************************** 1. row ***************************ENGINE: INNODB                      -- 表示存储引擎是 InnoDBENGINE_LOCK_ID: 139677990608088:1084:139677906555600  -- InnoDB 引擎中的锁标识符,通常由多个部分组成
ENGINE_TRANSACTION_ID: 4618                         -- 事务ID,表示锁属于哪个事务THREAD_ID: 228937                        -- 持有该锁的线程ID,可以用于跟踪哪个线程持有锁EVENT_ID: 23                            -- 事件ID,用于跟踪Performance Schema中的事件OBJECT_SCHEMA: test                          -- 数据库名称,此锁操作涉及的数据库为 "test"OBJECT_NAME: users                         -- 锁定的对象名称,这里是 "users" 表PARTITION_NAME: NULL                          -- 表分区名称,如果表有分区,显示分区名称;否则为 NULLSUBPARTITION_NAME: NULL                          -- 子分区名称,表无子分区则为 NULLINDEX_NAME: NULL                          -- 索引名称,如果锁作用在某个索引上,这里会显示索引名
OBJECT_INSTANCE_BEGIN: 139677906555600               -- 锁对象实例的内存地址,用于区分不同锁LOCK_TYPE: TABLE                         -- 锁的类型,这里表示锁是作用于整个表LOCK_MODE: IX                            -- 锁模式为 "Intent Exclusive" (IX),表示意向排他锁LOCK_STATUS: GRANTED                       -- 锁的状态,"GRANTED" 表示锁已授予成功LOCK_DATA: NULL                          -- 锁的附加数据,通常在行锁时会显示更多数据,这里为 NULL

3. 提交或回滚事务

在提交或回滚事务之后,再次查看 performance_schema.data_locks 表时,应该不再看到这个锁记录,因为锁已经被释放。

1.1 锁类型

锁类型依赖于存储引擎,在InnoDB存储引擎中按照锁的粒度分为,行级锁 RECORD和表级锁TABLE :
行级锁也叫 行锁,是对表中的某些具体的数据行进行加锁;
表级锁也叫 表锁,是对整个数据表进行加锁。

在之前版本的BDB存储引擎中还支持页级锁,锁定的是一个数据页,MySQL8中没有页级锁

 1.2 锁模式

锁模式,用来描述如何请求(申请)锁,分为共享锁(S)、独占锁(X)、意向共享锁(IS)、意向独占锁(IX)、记录锁、间隙锁、Next-Key锁、AUTO-INC 锁、空间索引的谓词锁等。

2. 共享锁和独占锁

InnoDB实现了标准的行级锁,分为两种分别是 共享锁(S锁) 独占锁(X锁) ,独占锁也称为排他锁。

  • 共享锁(S锁):允许持有该锁的事务读取表中的一行记录,同时允许其他事务在锁定行上加另一个共享锁并读取被锁定的对象,但不能对其进行写操作;
  • 独占锁(X锁):允许持有该锁的事务对数据行进行更新或删除,同时不论其他事务对锁定行进行读取或修改都不允许对锁定行进行加锁;

如果事务T1持有R行上的共享锁(S),那么事务T2请求R行上的锁时会有如下处理:

  • T2请求S锁会立即被授予,此时T1和T2都对R行持有S锁;
  • T2请求X锁不能立即被授予,阻塞到T1释放持有的锁

如果事务T1持有R行上的独占锁(X),那么T2请求R行上的任意类型锁都不能立即被授予,事务T2必须等待事务T1释放R行上的锁。

读锁是共享锁的一种实现,写锁是排他锁的一种实现。 

3. 意向锁

InnoDB 中的 意向锁(Intention Locks) 是一种元数据锁,用于协调不同事务对表级和行级锁的兼容性,确保表锁和行锁之间的并发操作不会产生冲突。意向锁不会直接锁定数据,而是用来表示某个事务将要已经在某些行上获取了特定类型的锁。

InnoDB 使用意向锁实现多粒度级别的锁,意向锁是表级别的锁,它并不是真正意义上的加锁,而只是在 data_locks 中记录事务以后要对表中的哪一行加哪种类型的锁(共享锁或排他锁),意向
锁分为两种:

  • 意向共享锁(IS,Intention Shared Lock): 表示事务打算在表的某些行上加共享锁(S 锁)。共享锁允许其他事务读取行,但不允许修改。

  • 意向排他锁(IX,Intention Exclusive Lock): 表示事务打算在表的某些行上加排他锁(X 锁)。排他锁禁止其他事务同时读取或修改被锁定的行。

当一个事务要在某个行上获取行级锁时,InnoDB 会在获取行锁之前首先在表级别上设置一个意向锁。这种意向锁的作用是声明该事务在这个表中会对某些行加锁。这样,当另一个事务想对整个表加一个表级锁(如表共享锁 S 或表排他锁 X)时,InnoDB 可以根据意向锁快速判断是否能授予表锁。举例:

  • 当事务1对表中的某行加排他锁(行 X 锁)时,系统会先在该表上设置一个意向排他锁(IX 锁)。
  • 当另一个事务2试图对整个表加表共享锁(S 锁)时,系统会检查表上的意向锁,如果发现有意向排他锁(IX),事务2的表共享锁请求会被阻塞,直到事务1释放其行锁和意向锁。

在请求锁的过程中,如果将要请求的锁与现有锁兼容,则将锁授予请求的事务,如果与现有锁冲突,则不会授予;事务将阻塞等待,直到冲突的锁被释放。意向锁的主要作用是在不同锁之间进行兼容性检测,表锁和意向锁的兼容性矩阵如下:

4. 索引记录锁

索引记录锁或称为精准行锁,顾名思意是指索引记录上的锁,如下SQL锁住的是指定的一行,例如,当你使用 SELECT FOR UPDATE 语句查询并锁定一行时,InnoDB 会对通过索引找到的记录加上排他锁(X 锁),直到事务提交或回滚时才会释放这些锁。

索引记录锁总是锁定索引行,在表没有定义索引的情况下,InnoDB创建一个隐藏的聚集索引,并使用该索引进行记录锁定,当使用索引进行查找时,锁定的只是满足条件的行,如图所示: 

5. 间隙锁

间隙锁锁定的是索引记录之间的间隙,或者第一个索引记录之前,再或者最后一个索引记录之后的
间隙。如图所示位置,根据不同的查询条件都可能会加间隙锁:

间隙锁通常用于防止幻读现象的发生,尤其是在 REPEATABLE READ 隔离级别下。

例如有如下SQL,锁定的是ID(10,20)之间的间隙,注意不包括10和20的行,目的是防止其他事务将ID值为15的列插入到列 account 表中(无论是否已经存在要插入的数据列),因为指定范围值之
间的间隙被锁定;

  • 只防插入,不防更新:间隙锁的作用是防止其他事务在锁定的“间隙”中插入新记录,但它不会阻止对现有记录的修改。换句话说,间隙锁针对的是插入操作,而不是更新操作。
  • 锁定的范围是开区间:间隙锁锁定的是索引记录之间的区域,是一个“开区间”。比如,索引记录 (3, 5) 之间的间隙是指 3 < x < 5 的所有范围。

对于使用唯一索引查询到的唯一行,不使用间隙锁,如下语句,id列有唯一的索引,只对id值为100的行使用索引记录锁:

 6. 临键锁

Next-key 锁是索引记录锁和索引记录之前间隙上间隙锁的组合,如图所示:

临键锁(Next-Key Lock) 是 InnoDB 存储引擎中的一种锁定机制,用来在高并发事务下保护数据的完整性和一致性。它结合了记录锁(Record Lock) 间隙锁(Gap Lock)的特点,既锁定了实际存在的记录,也锁定了记录之间的“间隙”,从而防止其他事务对这些范围进行插入、更新、删除等操作。

临键锁主要用于避免幻读现象,特别是在REPEATABLE READ隔离级别下,确保查询结果的一致性。

临键锁的工作方式是将索引记录及其周围的间隙一起锁定。在InnoDB中,临键锁在涉及范围查询时特别有效。假设一个表中有索引 (1, 3, 5),如果一个事务执行查询 SELECT * FROM table WHERE id > 1 FOR UPDATE,InnoDB 将会:

  • 锁定 id = 3id = 5 的索引记录(记录锁)。
  • 同时锁定 1 < id < 33 < id < 5 之间的空隙(间隙锁)。

这样做的目的是确保在该事务执行期间,其他事务无法插入 id=2id=4 这样的记录,从而避免了幻读。

7. 自增锁

AUTO-INC锁也叫自增锁是一个表级锁,服务于配置了 AUTO_INCREMENT 自增列的表。在插入数据时会在表上加自增锁,并生成自增值,同时阻塞其他的事务操作,以保证值的唯一性。需要注意的是,当一个事务执行新增操作已生成自增值,但是事务回滚了,申请到的主键值不会回退,这意味着在表中会出现自增值不连续的情况。


http://www.ppmy.cn/news/1540352.html

相关文章

10月18日,每日信息差

第一、现代汽车集团在上海举办了中国前瞻技术研发中心的发布及启新庆典&#xff0c;宣布成立其全资法人公司 —— 现代前瞻汽车技术开发&#xff08;上海&#xff09;有限公司。该中心是集团在海外建立的首个前瞻技术研发中心&#xff0c;专注于自动驾驶、智能座舱、共享出行等…

23种设计模式具体实现方法

提示&#xff1a;文章 文章目录 前言一、背景二、设计模式1、代理模式2、适配器模式2.1 总结 三、3.1 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 最近 二、设计模式 1、代理模式 参考的这篇文章&#xff0c;代理模式(Proxy) 同时这篇文章还引用了另…

嵌入式数据结构中顺序栈用法

第一:嵌入式C语言中栈特点 栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈),允许进行操作的一端称为“栈顶”,另一固定端称为“栈底”,当栈中没有元素时称为“空栈”。特点 :后进先出(LIFO)。

机器学习:opencv--人脸检测以及微笑检测

目录 前言 一、人脸检测的原理 1.特征提取 2.分类器 二、代码实现 1.图片预处理 2.加载分类器 3.进行人脸识别 4.标注人脸及显示 三、微笑检测 前言 人脸检测是计算机视觉中的一个重要任务&#xff0c;旨在自动识别图像或视频中的人脸。它可以用于多种应用&#xff0…

基于Springboot+Vue的宠物管理系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…

如何修改网络ip地址:一步步指南‌

在当今这个数字化时代&#xff0c;网络已成为我们日常生活与工作中不可或缺的一部分。无论是浏览网页、在线办公还是享受流媒体服务&#xff0c;稳定的网络连接和适当的IP地址管理都是确保良好体验的关键。然而&#xff0c;出于隐私保护、绕过地理限制或测试网络环境等需要&…

Python 爬虫实战与技巧分享--urllib

Python 爬虫实战与技巧分享–urllib 在当今信息时代&#xff0c;数据的价值日益凸显。Python 爬虫作为一种强大的数据获取工具&#xff0c;能够帮助我们从互联网上抓取各种有价值的信息。本文将结合具体代码示例&#xff0c;深入探讨 Python 爬虫的相关知识和关键要点。 一、…

湖南(满意度调研)综合性产业园区如何提升企业和创业者获得感?

湖南&#xff08;市场调研&#xff09;源点咨询认为&#xff0c;相对于专业性产业园来说&#xff0c;综合性产业园的园区运营工作的覆盖面及运营成本要高很多&#xff0c;运营回报率的时效性也要慢很多。 而从产业园区运营管理的双重目标约束是公共利益和经济利益最大化&#…