mysql锁机制及MVCC底层原理

news2024/12/28 17:42:10

一、锁介绍

  1. 按性能可分为乐观锁(适用于读多写少的情况下,如果是写多,导致过多cpu空转,影响性能)和悲观锁(适用于写多的情况)
  2. 按数据库操作粒度可分为表锁、页锁、行锁
  3. 按数据库操作类型可分为读锁和写锁(悲观锁)、意向锁

1、读锁(共享锁,S锁)

同一份数据,多个操作只能是读,会阻塞写,不会阻塞读,你可以在加了读锁之后在另一个事务中加读锁,一样是可以的,但是不要在update后面执行,因为update会加写锁,要等update事务结束才行,在任何隔离级别下都一样

2、写锁(排它锁,X锁)

select可以通过在最后面加上for update来加写锁,写锁会阻塞其它写锁和读锁

在非串行化事务隔离级别下,无论是加读锁还是写锁都可以正常读取数据 

3、行锁

每次锁住一行数据,开销大,加锁慢,支持的并发度高,因为要找寻符合条件的行进行加锁,所以加锁慢,粒度小,并发度自然就高

锁是加载索引上的,如果没有走索引加锁,很有可能行锁升级为表锁(rr级别下可能会升级成表锁rc级别下不会升级成表锁)

为什么rr级别下可能会升级成表锁rc级别下不会升级成表锁

由于加锁的字段是没有索引的,全表扫的是聚簇索引,为了在rr级别下是可重复读的,不会被其它事务修改而受影响,mysql会把扫描过的记录和主键之间的间隙都加锁,不一定能加上表锁,也有可能其它事务锁住了表中其它的数据记录

4、页锁

在BDB存储引擎下支持页锁,也就是底层数据结构的单个叶子节点的一页数据记录锁住,加锁范围相对较大,等待其它事务释放锁时间相对较长

5、表锁

每次加锁直接锁住整张表,开销小,加锁快,不会出现死锁,并发度低,一般用作数据迁移,下面看看如果一个表有其它事务在进行写操作(写锁),能不能正常对表加读锁或者写锁(可重复读级别下演示):

 把读锁释放,事务B再次加写锁,看看什么情况:

lock table 表名称 read(write),表名称2 read(write);#手动对整张表添加读锁或者写锁
show open tables;#查看上过锁的表
show open tables where in_use > 0;#查看上过锁的表
unlock tables;#删除表锁

6、意向锁

在对表加表锁时需要判断表中是否存在其它事务加的锁而设的标志位,为了提高加表锁的效率,不必逐行去判断有没有加锁

意向共享锁:对表加锁时,表中有读锁的标志位

意向排它锁:对表加锁时,表中有写锁的标志位

7、间隙锁

间隙锁就是在锁定区间内,所有的空隙区间都无法插入新的数据(只有在可重复读级别下才存在间隙锁),举例说明:

现有间隙区间(4,18),(18,26),(26,正无穷)三个区间

select * from account where id = 16 for update;
select * from account where id = 100 for update;

第一条sql的间隙区间范围是 (4,18),其它事务在(4,18)区间内插入记录会陷入等待,第二条sql的间隙区间范围是(26,正无穷),其它事务在(26,正无穷)区间内插入记录会陷入等待

8、临建锁

就是行锁和间隙锁的组合,还是按照间隙锁的数据例子,有这样一条sql

select * from account where id = 16 for update;

这样它的区间加锁范围就是4<id<=18都会加锁,这是区间就有(4,18]

myisam存储引擎,读操作之前会给所有表加读锁,在执行insert、update、delete会给涉及的表加写锁

innodb存储引擎,读操作不会给所有表加读锁(非串行化),在执行insert、update、delete会给涉及的表加写锁

二、锁优化

查看mysql所有数据库当前有多少锁等待

show status like 'innodb_row_lock%';

1、锁基本数量参数

Innodb_row_lock_current_waits:当前正在等待锁定的数量

Innodb_row_lock_time:从系统启动到现在锁定时间总长度

Innodb_row_lock_time_avg:每次等待花的平均时间

Innodb_row_lock_time_max:从系统启动到现在等待最长一次花的时间

Innodb_row_lock_waits:系统启动到现在所有锁等待的数量

一般分析这三个参数

Innodb_row_lock_time_avg (等待平均时长)

Innodb_row_lock_waits (等待总次数)

Innodb_row_lock_time(等待总时长)

2、查看锁的具体详细信息

具体分析有多少锁等待,

#查看事务
select * from INFORMATION_SCHEMA.INNODB_TRX;
#查看锁,8.0之后需要换成这张表performance_schema.data_locks
select * from INFORMATION_SCHEMA.INNODB_LOCKS;
#查看锁等待,8.0之后需要换成这张表performance_schema.data_lock_waits
select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

#查看锁等待详细信息
show engine innodb status;

 

 这时候去查询有三个事务,两个事务状态是锁等待,可以根据try_query字段查看哪句sql让事务陷入了锁等待

 第二个结果集,锁id是相同的,而事务id不同,说明三个事务正在尝试获取同一把锁,lock_mode是X,也就是写锁,针对account表主键假的写锁(如果只有一个事务加锁,则一行记录都没有,因为没有锁等待)

 第三个结果集,意思是事务id为522122请求时被事务id为522121和522118的事务加锁阻塞;事务522121正请求时被事务id为522118的事务加锁阻塞

 查看show engine innodb status;的Status字段关键信息截图

3、死锁情况 

 

 

 

 有些场景下mysql检测不到死锁我们可以使用之前的命令查询到trx_mysql_thread_id,手动kill

#释放锁,trx_mysql_thread_id可以从INNODB_TRX表里查看到
kill trx_mysql_thread_id;

 总结:

尽量可能用到索引加锁,否则行锁会升级成表锁

缩小索引加锁范围,减少锁的粒度,避免间隙锁

合理缩小事务,减少锁等待时间,加锁逻辑都放到事务最后执行

尽可能用低的事务隔离级别,意味着性能高

三、MVCC机制

临时事务:

begin/start transaction开始事务时并不会马上生成事务,查询操作会生成一个临时事务(待验证)

1、undo log版本链和read view机制详解

undo log每条日志版本都会加上trx_id和roll_pointer,以account表为例,具体如下

read view在可重复读级别下,从事务第一次查询开始就生成了read view,该视图在事务结束前都不会发生变化,而读已提交级别下,read view在同一事务内每查询一次,read view都会重新生成,视图生成规则:

由所有未提交的事务id数组加上已创建最大事务id组成,事务中任何查询sql结果都需要从undo log最新版本链中获取

2、版本链比对规则

  • 如果在最新版本链往上找,找到的trx_id是trx_id<min_trx_id(说明是已经提交的数据,这个版本数据可见
  • 如果在最新版本链往上找,找到的trx_id是trx_id>max_trx_id(如果trx_id是当前事务id,这个是可见的,如果不是当前事务id,说明是还未创建的事务)
  • 如果在最新版本链往上找,找到的trx_id是min_trx_id<trx_id<max_trx_id,要分两种情况,因为有个未提交事务id视图数组;(如果在视图数组中,说明是未提交事务;如果在视图数组外,说明是已提交的事务生成的版本)

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

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

相关文章

UE4/5动画系列(1.模板制作)

目录 动画模板制作 同步模板组制作 有模板做什么都方便&#xff0c;所以这里我们做一个动画蓝图的模板&#xff08;动物专用&#xff09; 动画模板制作 第一步创建一个动画蓝图的模板 然后找到第三人称的模板&#xff0c;将其模板的蓝图改名&#xff1a; 在动画蓝图的模板里…

团体程序设计天梯赛-练习集L2篇②

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的普通人。 &#x1f3c0;个人主页&#xff1a;陈童学哦CSDN &#x1f4a1;所属专栏&#xff1a;PTA &#x1f381;希望各…

首个跨云元数据KV存储Xline正式进入CNCF沙箱

2023年6月13日&#xff0c;云原生计算基金会&#xff08;CNCF&#xff09;宣布Xline正式被纳入CNCF沙箱(Sandbox&#xff09;项目。Xline是由达坦科技&#xff08;DatenLord&#xff09;于2022年年底推出的开源项目&#xff0c;是一个用Rust语言写就的&#xff0c;用于元数据管…

hello算法笔记之图

一、图的基础知识 图是一种非线性数据结构&#xff0c;由「顶点 Vertex」和「边 Edge」组成。 1.图的类型&#xff1a; 根据边是否具有方向可以分为有向图&#xff0c;无向图 根据所有顶点是否连通可以分为连通图&#xff08;对于连通图&#xff0c;从某个顶点出发&#xf…

gdb系列-入门篇-day01

gdb基础命令 一个程序要被调试&#xff0c;编译的时候要加上-g选项&#xff0c;例如gcc -g … 先准备一个调试的小代码 #include <stdio.h>int hello() {printf("hello\n");return 0; }int main() {int a[5] {1,2,3,4,5};hello();for(int i0; i<5; i){pri…

springboot使用@Valid 和 @Validated 注解校验详解以及编写一个自定义全局异常类

package com.test.springvalid.config;import lombok.Data; import java.util.HashMap; import java.util.Map;/*** 通用返回结果&#xff0c;服务端响应的数据最终都会封装成此对象* param <T>*/ Data public class R<T> {private Integer code; //编码&#xff1…

Mybatis源码分析_Mapper接口是如何实例化的 (2)

我们在使用Springmybatis的时候&#xff0c;经常都是直接写一个接口和一个对应的 ***Mapper.xml文件&#xff0c;然后业务代码就可以直接注入这个接口了。它是如何做到的呢&#xff1f; 接口&#xff1a; xml 想搞清楚这个问题&#xff0c;那还是要从Mybatis底层源码进行分析的…

智能小车使用IIC屏幕做动作显示界面

一、简介 使用0.96寸IIC屏幕作为遥控动作的显示界面。 外设引脚 stm32f103c8t6单片机IIC引脚有两组 使用I2C1&#xff0c;对应的时钟与数据线分别为PB6、PB7。 IIC屏幕指令 // OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel // OLED_WR_Byte(0x00,OLED_CMD);//---se…

07- c语言指针 (C语言)

一 指针的引入 1、一般把内存中的一个字节称为一个内存单元。 2、为了正确地访问这些内存单元&#xff0c;必须为每个内存单元编上号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址&#xff0c;通常也把这个地址称为指针。 3、如果在程序中定义…

车载网络测试 - CANCANFD - 基础篇_03

十、发送方式与过滤方式 1、广播发送及规则 我们以小组讨论现场为例来说明CAN总线广播发送规则&#xff1a; 1&#xff09;一个房间代表同一路CAN总线&#xff0c;每一个小组代表一个CAN Node&#xff0c;每一个小组成员发言代表发送一帧CAN报文&#xff0c;对所有的小组成员进…

生成对抗网络

1 GAN基本概念 1.1 GAN介绍 GAN的英文全称是Generative Adversarial Network&#xff0c;中文名是生成对抗网络。它由两个部分组成&#xff0c;生成器和鉴别器&#xff08;又称判别器&#xff09;&#xff0c;生成网络&#xff08;Generator&#xff09;负责生成模拟数据&…

【Python】异常处理 ④ ( 异常处理 else 语句 | 异常处理 finally 语句 )

文章目录 一、Python 异常捕获 else 语句1、异常捕获 else 语句2、代码示例 - 没有触发 else 语句的情况3、代码示例 - 触发 else 语句的情况 二、Python 异常捕获 finally 语句1、异常捕获 finally 语句2、代码示例 - 出现异常后执行 finally 语句 一、Python 异常捕获 else 语…

展示和标注图像:探索Gradio AnnotatedImage模块的功能

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

代码生成器原理分析

代码生成器原理分析 理解代码生成器的需求和实现思路掌握freemaker的使用 理解数据库中的元数据完成环境搭建工作 浅谈代码生成器 概述 在项目开发过程中&#xff0c;关注点更多是在业务功能的开发及保证业务流程的正确性上&#xff0c;对于重复性的代码编写占据了程 序员…

指标综合评价(定性指标定量化、指标正相关化、赋权重)

目录 一、定性指标定量化 二、将指标同型化 线性比例变换法 极差变换法 二、评价指标赋予权重 三、综合评价 战斗机性能的综合评价问题 例&#xff1a;战斗机的性能指标主要包括最大速度、飞行半径、最大负载、隐身性能、垂直起降性能、可靠性、灵敏度等指标和相关费用。…

Vue+Element UI 生鲜管理系统简介及项目搭建,页面布局(一)

文章目录 浅谈一、背景二、搭建创建vue项目vue项目结构简介安装Element UI库安装axios安装querystring安装normalize.css安装echarts运行删除无用组件基础css样式导入 三、页面布局配置路由布局flex布局&#xff08;弹性盒子&#xff09;固定布局固定布局配置路由 浅谈 自从入…

【Rust】2、实战:文件、网络、时间、进程-线程-容器、内核、信号-中断-异常

文章目录 七、文件和存储7.2 serde 与 bincode 序列化7.3 实现一个 hexdump7.4 操作文件7.4.1 打开文件7.4.2 用 std::fs::Path 交互 7.5 基于 append 模式实现 kv数据库7.5.1 kv 模型7.5.2 命令行接口 7.6 前端代码7.6.1 用条件编译定制要编译的内容 7.7 核心&#xff1a;LIBA…

【Java高级语法】(十五)lambda表达式:给你一颗语法糖Lambda,解析函数式编程的杰作~

Java高级语法详解之lambda表达式 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法结构3.2 案例3.2.1 无参Lambda3.2.2 带有一个参数3.2.3 带有多个参数3.2.4 方法引用的简化形式 4️⃣ 应用场景5️⃣ 优化技巧6️⃣ 原理7️⃣ 注意性能问题&#x1f33e; 总结 1️⃣ 概念 Java …

架构设计第十一讲:架构之高并发:限流

架构设计第十一讲&#xff1a;架构之高并发&#xff1a;限流 每个系统都有服务的上线&#xff0c;所以当流量超过服务极限能力时&#xff0c;系统可能会出现卡死、崩溃的情况&#xff0c;所以就有了降级和限流。限流其实就是&#xff1a;当高并发或者瞬时高并发时&#xff0c;为…

rabbitmq第三课-RabbitMQ高级功能详解以及常用插件实战

一、选择合适的队列. 实际上是可以选择三种队列类型的&#xff0c;classic经典队列&#xff0c;Quorum仲裁队列&#xff0c;Stream流式队列。 后面这两种队列也是RabbitMQ在最近的几个大的版本中推出的新的队列类型。3.8.x推出了Quorum仲裁队列&#xff0c;3.9.x推出了Stream流…