史上最易懂的mysql锁 、mvvc分析

1 mysql中的锁类型:

1) 表锁

表共享锁(S):表级别的读锁,表共享锁之间是兼容的。
表排他锁(X): 表级别的写锁,表排他锁和任何锁(包括表排他锁)都不兼容(不包括意向锁)。
意向排他锁(IX): 获取行排他锁之前必须获取的意向排他锁,这个锁是用了快速指示当前是否存在行排他锁,而不用在表中遍历每行数据判断当前行是否有行锁。
意向共享锁(IS): 获取行共享锁之前必须获取得意向共享锁,这个锁是用了快速指示当前是否存在意向共享锁,而不用在表中遍历每行数据判断当前行是否有行排他锁。

2) 行锁

行锁(R)主要是针对唯一索引(包括主键),行锁也分行共享锁(S)、行排他锁(X)。

3) 间隙锁

间隙锁(GAP):指锁定一个范围区间,主要用来接解决幻读问题。
插入意向锁(INSERT_INTENTION):它不是意向锁,意向锁是表锁,它是一种特殊的间隙锁,在数据插入的时候需要先获取插入意向锁。
4) 临键锁(NEXT-KEY) : 它可以看成一种组合锁,相当于行锁+间隙锁。普通的索引列(非唯一索引)就是加临键锁。间隙锁是用来锁住一个区间的,防止这个区间内插入其他数据,普通索引是可以重复的,需要锁住自身,所以还需要行锁,而唯一索引本身是有唯一性的,不能插入重复数据,只需要锁住间隙就可以了,不需要锁住自己本身。

2 具体验证

现在有一个表stu,其中的age字段有索引,现在针对age字段做锁实验。stu表中目前有如下这些数据,注意:每次写数据后都要恢复成下面的初始化数据。

CREATE TABLE `stu` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`age` int DEFAULT NULL,PRIMARY KEY (`id`),KEY `age_index` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=125 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;select * from stu;
+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | NULL |   10 |
|  3 | 23   |   24 |
|  6 | NULL |   32 |
|  7 | 23   |   45 |
+----+------+------+

1) 间隙锁with间隙锁

间隙锁和间隙锁之间是兼容的,即可以同时同一个区间加锁,不会有锁竞争。

先在会话1中开启一个事务,更新age=24的记录,此时会获取到[10,32)这个区间的插入间隙锁,此时先不提交事务,然后在新会话2中尝试更新[10,32)区间的一条数据age=25的记录,此时会话2中sql脚本执行正常(尽管此数据不存在)、没有被阻塞。

// 会话1
COMMIT;
update stu set `name` ='hi' WHERE age=24//会话2
update stu set `name` ='hi' WHERE age=25

2) 插入意向锁with插入意向锁

插入意向锁和插入意向锁(也是一种间隙锁)之间是兼容的,只要不是唯一索引(包括主键)冲突,可以直接插入,不会有锁竞争。

先在会话1中开启一个事务,插入一条age=15的记录,此时会获取到[10,24)这个区间的插入意向锁,此时先不提交事务,然后在新会话2中尝试插入[10,24)区间的一条数据age=16的记录,此时会话2中数据插入成功、没有被阻塞。

//会话1
begin;
INSERT stu (`name`,age) values ('he',15);//会话2
INSERT stu (`name`,age) values ('he',16);

3) 间隙锁with插入意向锁

间隙锁和插入意向锁之间有锁竞争,但只有在先有间隙锁再申请插入意向锁时才会不兼容,有锁竞争;反之在先有插入意向锁再申请间隙锁是不会有锁竞争的,是兼容的。
(1)先在会话1中开启一个事务,删除记录age=25的记录(尽管此数据不存在),此时会获取到[32,45)这个区间的间隙锁,此时先不提交事务,然后在新会话2中尝试插入[32,45)区间的一条数据age=36的记录,此时会话2中数据一直被阻塞,直到会话1的事务提交。这充分证明了先有间隙锁再申请插入意向锁,锁不兼容.

//会话1
BEGIN;
DELETE from stu WHERE age=35;
//会话2
INSERT stu (`name`,age) values ('he',36); //被阻塞

(2) 其他很多技术贴都说间隙锁的锁区间是左开右闭,但我实验的结果是左闭右开。
先在会话1中开启一个事务,删除记录age=25的记录(尽管此数据不存在),此时会获取到[32,45)这个区间的间隙锁,此时先不提交事务,然后在新会话2中尝试插入[32,45)区间的一条数据age=32的记录,此时插入失败、被阻塞,然而在新会话3尝试插入另一条数据age=45的记录则成功插入、没被阻塞。按照那些技术贴的说法,应该age=45的数据插入失败被阻塞,age=32的数据插入成功,但事实却不是如此。

//会话1
BEGIN;
DELETE from stu WHERE age=35;
//会话2
INSERT stu (`name`,age) values ('he',32); //被阻塞
//会话3
INSERT stu (`name`,age) values ('he',45); //成功插入

(3)先在会话1中开启一个事务,插入一条记录age=27的记录,此时会获取到[25,32)这个区间的插入意向锁,此时先不提交事务,然后在新会话2中尝试在[25,32)区间更新的一条数据age=29的记录(尽管此数据不存在),此时会话2中sql脚本正常返回、没有被阻塞。这充分证明了先有插入意向锁再申请间隙锁,锁兼容.

//会话1
BEGIN;
INSERT stu (`name`,age) values ('he',32); //会话2
UPDATE stu set `name`='haha' WHERE age=29;//正常返回、不阻塞

3 mvvc

网上对mvvc的解释太复杂了,我这里简单说下的行为结果。
mvvc中读提交可重复读这两种隔离级别中有不同的行为。
读提交 :每次的读都是当前读,即每次都读当前最新的已提交数据。
可重复:可重复读是快照读,第一次读和当前读一样,读此时的最新的已提交数据,不同点在于之后的第2~n次读。第一次之后的第2~n次读出的数据不会再变化,这时读出的数据是第一次读的快照,它和第一次读的数据始终是一样的,不再关心第一次读之后的已提交数据。每次读数是一样的,这就是名副其实的可重复读
在可重复读隔离级别下, 普通的select 语句是快照读,而updatedeleteinsert (如果把update delete insert判断是否能写数据的过程看成读的话) select (for update)/(lock on share mode) 都是当前读。

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

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

相关文章

关于python包导入问题的重思考

将顶层目录直接设置为一个包 像这样,每一个文件从顶层包开始导入 这样可以解决我的问题,但是要注意的时,要避免使用出现上下级出现同名包的情况,比如: AutoServer--AutoServer--__init__.py--__init__.py这种情况下…

腾讯云的身份证核验,找不到这个类

系统接入腾讯云的sdk,Class ‘TencentCloud\Common\Credential’ not found 以下方法核对一下看有没有做错,如果没有需要重启一下守护一般是能解决问的 这个错误表明PHP代码试图加载一个名为TencentCloud\Common\Credential的类,但是在指定…

绿联云NAS一些探索(1):SSH、包管理器探测、安装docker-compose等

绿联云NAS一些探索SSH、包管理器探测、安装docker-compose等 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https:…

AI图书推荐:《如何利用ChatGPT在线赚钱》

这本书《如何利用ChatGPT在线赚钱》($100m ChatGPT_ How To Make Money Online With ChatGPT -- Sharp, Biily -- 2023 )主要阐述如何利用ChatGPT这一强大的语言模型工具在互联网上创造收入。 以下是各章节内容的概要: **引言** - 介绍了Chat…

STM32F103单片机工程移植到航顺单片机HK32F103注意事项

一、简介 作为国内MCU厂商中前三阵营之一的航顺芯片,建立了世界首创超低功耗7nA物联网、万物互联核心处理器浩瀚天际10X系列平台,接受代理商/设计企业/方案商定制低于自主研发十倍以上成本,接近零风险自主品牌产品,芯片设计完成只…

spring整合kafka

原文链接&#xff1a;spring整合kafka_spring集成kafka-CSDN博客 1、导入依赖 <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><version>2.5.10.RELEASE</version> </depende…

Arthas Profiler 事件监控场景介绍

CPU 使用情况 (cpu) 场景描述&#xff1a; 当应用程序响应缓慢或者CPU使用率异常高时&#xff0c;开发者需要找出导致高CPU消耗的具体方法调用。通过监控CPU使用情况&#xff0c;可以识别出那些占用大量CPU时间的热点方法。 使用Arthas的步骤&#xff1a; 启动CPU profiler:…

编译等底层知识

目录 一. GCC命令语句大全 二. GCC编译4个阶段 三. makefile的使用 四. CMake 五. GNU工具链开发流程图 六. Keil中的地址段 七. 静态库和动态库 一. GCC命令语句大全 -c只编译源文件&#xff0c;生成目标文件&#xff08;.o 文件&#xff09;&#xff0c;不进行链接。…

CC++内存管理【new和delete操作符的详细分析】【常见面试题】

C/C内存管理 1.C/C内存分布 我们先来看一段代码&#xff0c;来了解一下C/C中的数据内存分布。 # include <stdlib.h>int globalVar 1; static int staticGlobalVar 1; // 比globalVar还要先销毁,同一个文件下后定义的先析构 // 全局变量存在 数据段&#xff08;静态…

[Unity]播放音频卡顿问题

记录一个问题&#xff1a; 游戏内播放完音频A再去循环播放音频B&#xff0c;在协程里使用等待n秒来实现拼接&#xff0c;发现在个别手机上会有卡顿的问题&#xff0c;盲猜是和帧率有关。 这是最初的实现方案&#xff1a; IEnumerator IEPlayAudio(){if(ASOnBeginDrag ! null)…

VSCode+Vite+Vue3断点调试

目录 lunch.json创建 vite.config.ts 打断点运行 lunch.json创建 首先&#xff0c;点击VSCode左上角&#xff0c;甲壳虫运行的按钮&#xff0c;然后点击运行与调试&#xff0c;选择chrome浏览器&#xff0c;修改成一下配置。 { // 使用 IntelliSense 了解相关属性。 // 悬停…

codeforces round 949 div2

A Turtle and Piggy Are Playing a Game 题目&#xff1a; 思路&#xff1a;输出2的幂次b使得2^b为最大的不超过x的数 代码&#xff1a; #include <iostream>using namespace std;const int N 2e5 10;void solve() {int l, r;cin >> l >> r;if(r % 2) …

vscode 运行和调试

vscode使用断点 1.安装并激活扩展 Debugger for Chrome (弃用 --> JavaScript Debugger)Debugger for Firefox 2. 配置config文件 打开 config/index.js 并找到 devtool property。将其更新为&#xff1a; 如果你使用的是 Vue CLI 2&#xff0c;请设置并更新 config/in…

SpringBoot Redis读写与数据序列化 RedisTemplate 与 StringRedisTemplate 防转字节

介绍 RedisTemplate 对象在底层默认会转成字节&#xff0c;造成了内存的开销很大&#xff0c;这是他底层进行处理的,造成可读性差&#xff0c;如需要转成简单的字符串存储需要进行序列化的配置。 RedisTemplate 配置类 Configuration public class RedisConfig {Beanpublic …

OpenGL系列(五)纹理贴图

概述 OpenGL纹理是一种在三维图形中应用纹理映射的技术。纹理是一张图像&#xff0c;可以应用到三维模型的表面上&#xff0c;从而使得模型看起来更加真实和具有细节。通过纹理映射&#xff0c;可以将图像的像素值与三维模型的顶点进行匹配&#xff0c;从而为模型的表面增加细节…

Java并发编程之由于静态变量错误使用可能导致的并发问题

Java并发编程之由于静态变量错误使用可能导致的并发问题 1.1 前言1.2 业务背景1.3 问题分析1.4 为什么呢&#xff1f;1.5 修复方案2 演示示例源码下载 1.1 前言 我们知道在 Java 后端服务开发中&#xff0c;如果出现并发问题一般都是由于在多个线程中使用了共享的变量导致的。…

JVM相关:Java内存区域

Java 虚拟机&#xff08;JVM)在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。 Java运行时数据区域是指Java虚拟机&#xff08;JVM&#xff09;在执行Java程序时&#xff0c;为了管理内存而划分的几个不同作用域。这些区域各自承担特定的任务&#xff0c…

Day23 自定义对话框服务

​本章节实现了,自定义对话框服务的功能 当现有的对话框服务无法满足特定需求时,我们可以采用自定义对话框的解决方案,以更好地满足一些特殊需求。 一.自定义对话框主机服务步骤 在Models 文件夹中,再建立一个 IDialogHostService 接口类,继承自 IDialogService 对话框服…

计算两个LocalDateTime的相差时长

在Java中&#xff0c;你可以使用java.time.Duration类来计算两个LocalDateTime对象之间的时间差。以下是一个示例代码&#xff0c;展示了如何计算两个LocalDateTime实例之间相差的时长&#xff1a; import java.time.Duration; import java.time.LocalDateTime;public class D…

绝对实用Linux命令行下的文件夹逐层创建术,从小白到大神的必学技能

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 基础篇&#xff1a;初识Linux文件系统 在深入了解如何在Linux中逐层创建文件夹之前&#xff0c;需要对Linux的文件系统有一个基本的认识。Linux文件系统以其树状结构而著称&#xff0c;其中/&#xff08;根目录&…