【MYSQL篇】mysql中相关锁和MVCC详解

news2024/12/23 2:01:11

文章目录

  • 前言
  • MVCC
    • 1、第一个事务
    • 2、第二个事务
    • 3、第三个事务
    • 4、第四个事务
    • 5、第五个事务
  • InnoDB 常见的几种锁机制
    • 共享锁
    • 排它锁
    • 意向锁
    • 记录锁
    • 间隙锁
    • 临键锁
  • 小结


前言

数据库的锁是在多线程高并发的情况下用来保证数据稳定性和一致性的一种机制。MySQL 根据底层存储引擎的不同,锁的支持粒度和实现机制也不同。MyISAM 只支持表锁,InnoDB 支持行锁和表锁。目前 MySQL 默认的存储引擎是 InnoDB,这里主要介绍 InnoDB 的锁。上一篇文章,我们对 MySQL 的事务进行了详细的阐述,也顺带提到了 MVCC,在介绍锁之前,我们先来聊聊 MVCC 。

MVCC

要让一个事务前后两次读取的数据保持一致,那么我们可以在修改数据的时候给它建立一个备份或者叫快照,后面再来读取这个快照就行了。

问题:这个快照什么时候创建?读取数据的时候,怎么保证能读取到这个快照而不是最新的数据?这个怎么实现呢?

MVCC 的核心思想是: 我可以查到在我这个事务开始之前已经存在的数据,即使它在后面被修改或者删除了。在我这个事务之后新增的数据,我是查不到的。

InnoDB 为每行记录都实现了两个隐藏字段:

DB_TRX_ID:插入或更新行的最后一个事务的事务 ID,事务编号是自动递增的(我们把它理解为创建版本号,在数据新增或者修改为新数据的时候,记录当前事务 ID)。

DB_ROLL_PTR:回滚指针(我们把它理解为删除版本号,数据被删除或记录为旧数据的时候,记录当前事务 ID)。

接下来我们就来详细说说通过这两个版本号的控制,保证一个事务两次读取的数据是一致的。

1、第一个事务

初始化数据。

Transaction 1
begin; 
insert into user values(NULL,'mayun') ; 
insert into user values(NULL,'tory') ; 
commit;

此时的数据,创建版本是当前事务 ID,删除版本为空:

idname创建版本删除版本
1mayun1undefined
2tory1undefined

2、第二个事务

执行第 1 次查询,读取到两条原始数据,这个时候事务 ID 是 2:

Transaction 2 
begin; 
select * from user; -- (1) 第一次查询

3、第三个事务

插入数据:

Transaction 3 
begin; 
insert into user values(NULL,'tom') ; 
commit;

此时的数据,多了一条 tom,它的创建版本号是当前事务编号 :3。

idname创建版本删除版本
1mayun1undefined
2tory1undefined
3tom3undefined

第二个事务,执行第 2 次查询:

Transaction 2 
select * from user; --(2)第二次查询

MVCC 的查找规则:只能查找创建时间小于等于当前事务 ID 的数据,和删除时间大于当前事务 ID 的行(或未删除)。

也就是不能查到在我的事务开始之后插入的数据,tom 的创建 ID 大于 2,所以还是只能查到两条数据。

4、第四个事务

删除数据,删除了 id=2 ,name = tory这条记录。

Transaction 4 
begin; 
delete from user where id=2;
commit;

此时的数据,tory 的删除版本被记录为当前事务 ID,4,其他数据不变。

idname创建版本删除版本
1mayun1undefined
2tory14
3tom3undefined

在第二个事务中,执行第 3 次查询:

Transaction 2 
select * from user; --(3)第三次查询

查找规则:只能查找创建时间小于等于当前事务 ID 的数据,和删除时间大于当前事务 ID 的行(或未删除)。

也就是,在我事务开始之后删除的数据,所以 tory依然可以查出来。所以还是这两条数据。

5、第五个事务

执行更新操作,这个事务事务 ID 是 5。

Transaction 5 
begin; 
update user set name ='xiaoming' where id=1; 
commit;

此时的数据,更新数据的时候,旧数据的删除版本被记录为当前事务 ID 5(undo),

产生了一条新数据,创建 ID 为当前事务 ID 5。

idname创建版本删除版本
1mayun15
2tory14
3tom3undefined
1xiaoming5undefined

第二个事务,执行第 4 次查询:

Transaction 2 
select * from user; --(4) 第四次查询

查找规则:只能查找创建时间小于等于当前事务 ID 的数据,和删除时间大于当前事务 ID 的行(或未删除)。

因为更新后的数据 xiaoming创建版本大于 2,代表是在事务之后增加的,查不出来。

而旧数据 mayun的删除版本大于 2,代表是在事务之后删除的,可以查出来。

通过以上演示我们能看到,通过版本号的控制,无论其他事务是插入、修改、删除,第二个事务查询到的数据都没有变化。

InnoDB 常见的几种锁机制

共享锁

Shared Locks (共享锁):我们获取了一行数据的读锁以后,可以用来读取数据,所以它也叫做读锁。而且多个事务可以共享一把读锁。

那怎么给一行数据加上读锁呢?

我们可以用 select …… lock in share mode; 的方式手工加上一把读锁。

释放锁有两种方式,只要事务结束,锁就会自动事务,包括提交事务和结束事务。

验证一下,看看共享锁是不是可以重复获取。

Transaction 1
begin;
select * from user where id = 1 lock in share mode;

Transaction 2
begin;
select * from user where id = 1 lock in share mode;  --ok

排它锁

Exclusive Locks(排它锁):它是用来操作数据的,所以又叫做写锁。只要一个事务获取了一行数据的排它锁,其他的事务就不能再获取这一行数据的共享锁和排它锁。

排它锁的加锁方式有两种,第一种是自动加排他锁,可能是同学们没有注意到的:我们在操作数据的时候,包括增删改,都会默认加上一个排它锁。

还有一种是手工加锁,我们用一个 FOR UPDATE 给一行数据加上一个排它锁,这个无论是在我们的代码里面还是操作数据的工具里面,都比较常用。

释放锁的方式跟前面是一样的。

排他锁的验证:

Transaction 1
begin;
update user set name = 'xiaoming' where id=1;

Transaction 2
begin;
select * from user where id = 1 lock in share mode; -- BLOCKED
select * from user where id=1 FOR UPDATE; -- BLOCKED
delete  from user where id=1 ; -- BLOCKED

意向锁

当我们给一行数据加上共享锁之前,数据库会自动在这张表上面加一个意向共享锁。

当我们给一行数据加上排他锁之前,数据库会自动在这张表上面加一个意向排他锁。

反过来说:如果一张表上面至少有一个意向共享锁,说明有其他的事务给其中的某些数据行加上了共享锁。 如果一张表上面至少有一个意向排他锁,说明有其他的事务给其中的某些数据行加上了排他锁。

意向锁不会锁住任何东西,除非有进行全表请求的操作,否则不会锁住任何数据。存在的意义只是用来表示有事务正在锁某一行的数据,或者将要锁某一行的数据。

记录锁

记录锁(record Locks):锁住某一行,如果表存在索引,那么记录锁是锁在索引上的,如果表没有索引,那么 InnoDB 会创建一个隐藏的聚簇索引加锁。所以我们在进行查询的时候尽量采用索引进行查询,这样可以降低锁的冲突。

当我们对于唯一性的索引(包括唯一索引和主键索引)使用等值查询,精准匹配到一条记录的时候,这个时候使用的就是记录锁。

比如 where id = 1 4 7 10 。

我们使用不同的 key 去加锁,不会冲突,它只锁住这个 record。

间隙锁

间隙锁(Gap Locks):间隙锁是一种记录行与记录行之间存在空隙或在第一行记录之前或最后一行记录之后产生的锁。间隙锁可能占据的单行,多行或者是空记录。

通常的情况是我们采用范围查找的时候,比如在学生成绩管理系统中,如果此时有学生成绩 60,72,80,95,一个老师要查下成绩大于 72 的所有同学的信息,采用的语句是 select * from student where grade > 72 for update,这个时候 InnoDB 锁住的不仅是 80,95,而是所有在 72-80,80-95,以及 95 以上的所有记录。为什么会 这样呢?

实际上是因为如果不锁住这些行,那么如果另一个事务在此时插入了一条分数大于 72 的记录,那会导致第一次的事务两次查询的结果不一样,出现了幻读。所以为了在满足事务隔离级别的情况下需要锁住所有满足条件的行。

临键锁

Next-Key Locks(临键锁):NK 是一种记录锁和间隙锁的组合锁。既锁住行也锁住间隙。并且采用的左开右闭的原则。InnoDB 对于查询都是采用这种锁的。

举个例子说明:

现在有一个表a,如下:

image-20220127093631641

我们执行下面的操作:

# T1
START TRANSACTION WITH CONSISTENT SNAPSHOT; //1

SELECT * FROM a WHERE uid = 6 for UPDATE; //2

COMMIT;  //5


# T2
START TRANSACTION WITH CONSISTENT SNAPSHOT;  //3

INSERT INto a(uid) VALUES(11);
INSERT INto a(uid) VALUES(5);  //4
INSERT INto a(uid) VALUES(7);
INSERT INto a(uid) VALUES(8);
INSERT INto a(uid) VALUES(9);

SELECT * FROM a WHERE uid = 6 for UPDATE;

COMMIT;

ROLLBACK;

按照上面 1,2,3,4 的顺序执行会发现第 4 步被阻塞了,必须执行完第 5 步后才能插入成功。这里我们会很奇怪明明锁住的是uid=6 的这一行,为什么不能插入 5 呢?原因就是这里采用了 next-key 的算法,锁住的是(3,10)整个区间。

image-20220127093853903

小结

以上就是对于 mysql MVCC 以及 InnoDB 常见锁的一些知识总结,希望大家在看的时候也可以动手试试,这样更能体会,理解的更深刻。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/671900.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenGL

需要继承的两个类 #include <QOpenGLWidget> #include <QOpenGLFunctions_3_3_Core> class OpenGLWidget : public QOpenGLWidget,public QOpenGLFunctions_3_3_Core { Q_OBJECT public: explicit OpenGLWidget(QWidget *parent nullptr); virtual vo…

如何看待调查称半数年轻人存款不足10万?

文章目录 一、目前的存款在哪一个区间&#xff1f;你觉得存款难吗&#xff1f;2.1 自己的状态2.2 对理财的看法和态度 二、谈谈我为存款做出过哪些努力&#xff1f;三、除了个人因素外&#xff0c;有哪些因素影响到了年轻人的存款能力和存款意愿&#xff1f;四、要攒够多少存款…

【数据库原理与实践】CS系的实验期末考题(20222023)

2022&#xff1a; 学校管理数据库涉及四个关联表结构&#xff1a; 学生表 Student(Sno,Sname,Sdate,Ssex) &#xff0c;其中Sno学生编号&#xff0c;Sname学生姓名&#xff0c;Sdate出生年月&#xff0c;Ssex学生性别 。 课程表 Course(Cno,Cname,Tno) &#xff0c;其中Cno课…

(写自己语言的练手级应用)JSON(JavaScript Object Notation) 产生式(BNF)

写自己的开发语言时&#xff0c;很多人都会拿JSON当第一个练习对象 开源net json FJSON 解析工具https://dbrwe.blog.csdn.net/article/details/107611540?spm1001.2014.3001.5502 <json> :: <object> | <array> <object> :: "{" [ <me…

【OJ比赛日历】快周末了,不来一场比赛吗? #06.23-06.29 #13场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-06-23&#xff08;周五&#xff09; #5场比赛2023-06-24…

k8s中如何修改pod中mysql的连接数

(方法一) 临时更改设置最大连接数据&#xff08;建议先临时修改&#xff0c;项目没有问题之后再进行永久修改&#xff09; 使用Navicat连接上数据库&#xff0c;点击连接名——点击新建查询—— 查看最大连接数 show variables like ‘’%max_connections%‘’; 查看当前用户使…

vue中注册组件的两种方式(全局注册 局部注册)

vue 是一个完全支持组件化开发的框架&#xff0c; 组件之间可以进行相互的引用。vue 中组件的引用原则&#xff1a;先注册后使用。 1. 组件的注册 组件之间可以进行相互的引用&#xff0c;例如&#xff1a; 注册组件的的方式&#xff1a;分为“全局注册”和“局部注册”两种…

Git Bash 上传本地文件到Gitee(AI助力解决问题)

前言 消失了将近一个月&#xff0c;预祝大家端午节快乐&#xff01; 这篇文章主要介绍下在上传本地项目到gitee时出现的问题&#xff0c;以及借助AI解决问题。 Gitee是一个基于 Git 的代码托管和开发协作平台&#xff0c;它提供了代码仓库、代码审查、持续集成/持续部署 (CI/C…

开关电源——DCDC变换器设计

开关电源——DCDC变换器设计 对于DCDC变换器来说&#xff0c;最重要的部分也是唯一一个磁学元件——电感需要考虑。 直流传递函数 正如之前我们所说&#xff0c;电感电流在开关导通的时候增加的电流必须等于在开关关断时候的减少的电流&#xff0c;即在一个工作周期中不积累…

支付宝性能测试案例分析

双11过程当中&#xff0c;促销开启的第一分钟内支付宝的交易总额就突破了一亿元&#xff0c;短时间内大量用户涌入的情况下&#xff0c;如何保证用户的支付顺畅&#xff0c;是对支付宝应用系统的一个极大的挑战。 一、性能测试支付宝场景介绍 双11过程当中&#xff0c;促销开启…

企业级ChatGPT开发的三大核心内幕及案例实战(三)

企业级ChatGPT开发的三大核心内幕及案例实战(三) 2.3 Notion 问答对话AI案例演示及源码分析 Gavin老师:NLP_Matrix_Space 如图2-2所示,我们先看一下Notion 问答对话AI案例的效果。你问一个问题,它会进行回答,然后它会告诉你,信息来源在什么地方,要看具体的信息,可以…

ICLR 2023 | RevCol:给神经网络架构增加了一个维度!大模型架构设计新范式

点击蓝字 关注我们 关注并星标 从此不迷路 计算机视觉研究院 公众号ID&#xff5c;计算机视觉研究院 学习群&#xff5c;扫码在主页获取加入方式 论文地址&#xff1a;https://arxiv.org/pdf/2212.11696.pdf 项目代码&#xff1a;https://github.com/megvii-research/RevCol 计…

MySQL进阶SQL语句

目录 1.select&#xff08;显示表格中一个或数个字段的所有数据记录&#xff09; 2.distinct&#xff08;不显示重复的数据记录&#xff09; 3.where&#xff08;有条件查询&#xff09; 4.and 、or&#xff08;且、或&#xff09; 5. in&#xff08;显示已知的值的数据记…

Goby 漏洞发布|Weaver OA PluginViewServlet Authentication Bypass Vulnerability

漏洞名称&#xff1a;泛微OA办公系统 PluginViewServlet 认证绕过漏洞 English Name&#xff1a;Weaver OA PluginViewServlet Authentication Bypass Vulnerability CVSS core: 8.0 影响资产数&#xff1a;45034 漏洞描述&#xff1a; 泛微OA 是一款专业强大的多功能办公…

直播回顾:HVV经验分享与重保整体解决方案

6月15日&#xff0c;Coremail联合北京钛星数安科技有限公司举办【HVV经验分享与重保整体解决方案发布】直播分享会。 直播会上Coremail安全团队和钛星数安的刘平平老师为大家带来重保时期的防御实战经验&#xff0c;帮助企业充分做好重保的安全准备工作&#xff0c;安稳度过重保…

uniapp中如何给下拉框动态绑值

前言&#xff1a; 在项目中我们会经常遇到新增的功能&#xff0c;而新增的页面中就会有输入框、下拉框、文本域、日期选择框等等。那么在uniapp是如何给下拉框中调用接口动态绑值的呢&#xff1f;请往下看 &#x1f4a8; &#x1f497; uView官网&#xff1a;介绍 | uView 2.0…

kettle开发-Day39-超好用AI+算力组合-算力提升器

前言&#xff1a; 上一节我们提到采用标记新旧数据的数据状态来快速整理需对比的数据&#xff0c;再选择性插入更新来保证数据的完整性。强强联合&#xff0c;保证了数据的高效和可用。 但是日常中&#xff0c;也存在部分场景&#xff0c;我们表输入是没有唯一性主键的&#xf…

计算机服务器数据库中了Devos后缀勒索病毒怎么办,记住以下步骤!

近期&#xff0c;我接到许多企业的求助&#xff0c;企业的用友财务软件遭受了Devos后缀勒索病毒的攻击&#xff0c;导致企业的用友财务账套被加密&#xff0c;许多重要的数据都无法正常读取&#xff0c;给公司的正常运营和数据安全带来了严重威胁。一旦企业被devos勒索病毒攻击…

【计算机组成原理】RV32I指令集

目录 一、RISC-V架构概述 二、RV32I指令集概述 三、RV32I指令格式 四、21条运算指令 五、8条访存指令 六、8条转移指令 七、10条其他指令 八、RV32I的寻址方式 一、RISC-V架构概述 RISC-V指令集起源&#xff1a; 全新的、具有典型RISC特征的指令集架构&#xff0c;20…