MySQL 锁分类有哪些?一文带你详解!!

news2024/11/15 15:30:15

MySQL 锁

    • 全局锁
      • 全局锁的应用场景
      • 全局锁的缺点
    • 表级锁
      • 表锁
      • 元数据(MDL)锁
        • MDL 锁的问题
      • 意向锁
      • AUTO-INC 锁
    • 行级锁
      • 记录锁(Record Lock)
      • 间隙锁(Gap Lock)
      • 临键锁(Next-Key Lock)
      • 插入意向锁

首先让我们创建一张用户表,并插入一些数据:

CREATE TABLE userinfo (
  user_id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(50) NOT NULL,
  password VARCHAR(50) NOT NULL,
  email VARCHAR(100),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO userinfo (username, password, email) VALUES ('张三', 'password123', 'zhangsan@example.com');
INSERT INTO userinfo (username, password, email) VALUES ('李四', 'password456', 'lisi@example.com');
INSERT INTO userinfo (username, password, email) VALUES ('王五', 'password789', 'wangwu@example.com');

全局锁

插入全局锁的命令

flush tables with read lock

执行后,整个数据库就处于只读状态了,这时其他线程执行以下操作,都会被阻塞:

  • 对数据的增删改操作,比如 insert、delete、update等语句;
  • 对表结构的更改操作,比如 alter table、drop table 等语句。

比如此时我们想插入一条语句,但显示被读锁阻塞住了
在这里插入图片描述
执行释放锁之后的命令就可以插入成功了

unlock tables;

在这里插入图片描述

全局锁的应用场景

全局锁的应用场景主要应用于 全库逻辑备份

举个例子,如果不加读写锁的话

在备份用户表和商品表的时候,有一个用户购买了一件商品

就会导致备份的数据 是扣减前的用户余额 和 扣减后的商品余额 —— 用户余额没变,货却没了!

在这里插入图片描述

全局锁的缺点

加上全局锁后,数据库就变成了 只读状态

那么如果数据库有很多数据,备份就会花费很多时间,而且备份期间只能读数据而不能更新数据,就会导致业务的停滞

那有什么办法可以改进呢?

可以利用 MVCC 机制,在可重复读隔离级别下,开启事务后,会先创建一个 Read View,然后整个事务执行期间都会使用这个 Read View,同时也依然可以对数据进行更新操作。

这就是事务四大特性的 隔离性,这样备份期间备份的数据一直都是在开启事务时的数据。

注意,这需要能够适用 可重复读隔离级别 下的存储引擎,比如 Innodb。

但是 MyISAM 这种不支持事务的引擎,在备份数据库时就要使用全局锁的方法了。

表级锁

表锁

表锁有两种:

//表级别的共享锁,也就是读锁;
lock tables t_student read;

 //表级别的独占锁,也就是写锁;
lock tables t_stuent write;

这里的锁有点乱,我们可以做四次实验试试看

  1. 给表设置读锁,然后读数据,发现是正常没问题的
    在这里插入图片描述
  2. 然后我们进行写数据,发现被阻塞住了
    在这里插入图片描述

如图,这里我们给用户表设置了读锁,然后想写入一条数据,发现被阻塞住了

在这里插入图片描述

说明这里的本线程的表级别的读锁,会限制住本线程的写操作

  1. 我们解开表级锁,并设置读锁,然后再进行读操作

在这里插入图片描述
发现这里,阻塞住了,陷入了死锁状态,注意右下角的查询时间,这里是一直在查询没停止的(我只是截了个图),说明本线程的写锁也会限制住本线程的读操作

  1. 我们在写锁下进行写操作,正常没问题
    在这里插入图片描述

所以,可以看出来,表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。

所以,表锁的颗粒度是很大的,会影响到并发性能,尽量要避免使用,Innodb 牛逼的地方在于实现了颗粒度更细的行级锁。

元数据(MDL)锁

我们不需要显示的使用 MDL,因为当我们对数据库表进行操作时,会自动给这个表加上 MDL:

  • 当我们对一张表进行 CRUD 操作时,会对表加一个 元数据读锁;
  • 当我们对一张表的结构进行操作的时候,会对表加一个 元数据写锁

MDL 是为了保证当用户对表执行 CRUD 操作时,防止其他线程对这个表结构做了变更。

当有线程在执行 select 语句( 加 MDL 读锁)的期间,如果有其他线程要更改该表的结构( 申请 MDL 写锁),那么将会被阻塞,直到执行完 select 语句( 释放 MDL 读锁)。

反之,当有线程对表结构进行变更( 加 MDL 写锁)的期间,如果有其他线程执行了 CRUD 操作( 申请 MDL 读锁),那么就会被阻塞,直到表结构变更完成( 释放 MDL 写锁)。

MDL 锁的问题

MDL 是在事务提交之后才会释放的,也就是说,事务执行期间,MDL 是一直持有的

那如果数据库中有一个长事务,也就是开启之后一直没提交的事务,那当我们对表结构做变更操作的时候,可能就会出现一些问题:

  1. 线程A 开启了事务
  2. 线程A 执行了一条查询 select 语句,这时会加 MDL读锁
  3. 线程B 执行了一条查询 select 语句,这时不会阻塞,因为读读并不冲突
  4. 线程C 试图修改表字段,但此时事务A 并没有提交,所以 MDL 读锁就还占用着,此时线程C 就无法申请到 MDL 写锁,而导致阻塞
  5. 之后的线程 D、E、F 想要执行查询语句时,就会被阻塞住,然后数据库的线程就会爆满
    在这里插入图片描述

为什么写锁阻塞住,读锁也会被阻塞住?

因为 申请 MDL 锁的操作会形成一个队列,队列中 写锁获取的优先级高于读锁,一旦出现MDL 写锁等待,就会阻塞住该表的所有 CRUD 操作

在这里插入图片描述
所以,为了能安全的对表结构进行变更,在变更之前,我们要先看看数据库中的长事务,是否有事务已经对表加上了 MDL读锁,如果可以就考虑先 kill 掉他,然后再做变更。

意向锁

意向锁有两种:意向共享锁、意向排他锁:

  • 意向共享锁(Intention Shared Lock,IS):当一个事务请求获取一个行级锁或表级锁时,InnoDB会自动获取相应的表的意向锁。

这个锁表明事务打算以共享方式(读取)访问数据。其他事务在查询数据时,可以通过检查意向锁来快速确定是否有任何行级锁冲突,而无需检查表中每一行的锁状态。

  • 意向排他锁(Intention Exclusive Lock,IX):与意向共享锁类似,意向排他锁表明事务打算以排他方式(写入)访问数据。

当事务持有意向排他锁时,其他事务不能获取意向共享锁,从而防止其他读取操作的干扰。

也就是说,当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。

而普通的 select 是不会加行级锁的,普通的 select 语句是利用 MVCC 实现一致性读,是无锁的。

不过,select 也是可以对记录加共享锁和独占锁的,具体方式如下:

//先在表上加上意向共享锁,然后对读取的记录加共享锁 
select ... lock in share mode;  

//先表上加上意向独占锁,然后对读取的记录加独占锁 
select ... for update;

意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables … read)和独占表锁(lock tables … write)发生冲突。

表锁和行锁是满足读读共享、读写互斥、写写互斥的。

如果没有「意向锁」,那么加「独占表锁」时,就需要遍历表里所有记录,查看是否有记录存在独占锁,这样效率会很慢。

那么有了「意向锁」,由于在对记录加独占锁前,先会加上表级别的意向独占锁,那么在加「独占表锁」时,直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了独占锁,这样就不用去遍历表里的记录。

所以,意向锁的目的是为了快速判断表里是否有记录被加锁。

AUTO-INC 锁

auto-inc 锁(AUTO-INCREMENT lock),是InnoDB中用于处理自动增长(AUTO_INCREMENT)字段的一种特殊的锁定机制。当向表中插入数据时,如果该表包含有AUTO_INCREMENT列,并且你需要为这个列指定一个值,那么会涉及到auto-inc锁。

auto-inc锁的主要目的是确保在同一事务中插入的记录能够获得连续的AUTO_INCREMENT值。在并发插入的场景中,这可以避免插入操作之间的干扰,确保插入的顺序性。

行级锁

InnoDB 是支持行级锁的,而 MyISAM 是不支持的

记录锁(Record Lock)

记录锁是行级锁的一种,它针对数据表中的单个记录进行锁定,有 S 锁 和 X 锁之分,也就是共享锁和独占锁之分。

一个事务对一条记录加了 S 锁,其他事务可以加 S 锁,但不能加 X 锁

一个事务对一条记录加了 X 锁,其他事务 S 锁和 X 锁都不能加

记录锁通常是通过索引项来实现的,即数据库会锁定索引项来实现对行的锁定。

在这里插入图片描述

间隙锁(Gap Lock)

Gap Lock是锁定数据表中两个记录之间的空隙(即间隙锁)。

间隙锁只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的问题。

它用于防止其他事务插入新的记录,从而保护一个范围行的完整性。

Gap Lock不会锁定实际的行记录,而是锁定一个范围,阻止其他事务在这个范围内插入新行。

而且,间隙锁之间是不冲突的,可以相互兼容,只不过无法往间隙范围内插入数据

在这里插入图片描述

临键锁(Next-Key Lock)

Next-Key Lock是 记录锁 和 间隙锁 的组合。

它技能保护锁住的该条记录,又能阻止其他事务将其新纪录插入到被保护记录前面的间隙中

在这里插入图片描述

因为临键锁是包含 记录锁 + 间隙锁的,而间隙锁之间是可以相互兼容的,但记录锁就需要注意考虑 S 型 和 X 型的关系了

插入意向锁

插入意向锁是与上面的间隙锁对应生效的

如果一条记录的位置已经被其他事务加了间隙锁(当然,也包含临键锁中的间隙锁),那么,这个插入操作就会被阻塞,在此期间会生成一个 插入意向锁,表明有事务想要在某个区间插入新纪录,但是现在处于等待状态

比如事务 A 在一个区间内加了间隙锁,然后事务 B 想要在该区间插入一条语句,这时候发现有个间隙锁,于是就会生成一个 插入意向锁,然后将锁呢设置为等待状态。

MySQL 加锁的时候,会先生成锁结构,然后设置锁状态,锁状态为正常状态,就表示事务获取到了锁,如果为等待状态,就意味着没有获取到锁

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

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

相关文章

安卓开发板_联发科MTK开发评估套件串口调试

串口调试 如果正在进行lk(little kernel ) 或内核开发,USB 串口适配器( USB 转串口 TTL 适配器的简称)对于检查系统启动日志非常有用,特别是在没有图形桌面显示的情况下。 1.选购适配器 常用的许多 USB 转串口的适配器&#xf…

宝塔部署Vue项目解决跨域问题

一、前言 使用宝塔面板部署前端后端项目相比用命令行进行部署要简单许多,宝塔的可视化操作对那些对Linux不熟悉的人很友好。使用宝塔部署SpringBoot后端项目和Vue前端项目的方法如下: 1、视频教程 2、文字教程1 3、文字教程2 以上的教程完全可以按照步骤…

以太网交换机工作原理学习笔记

在网络中传输数据时需要遵循一些标准,以太网协议定义了数据帧在以太网上的传输标准,了解以太网协议是充分理解数据链路层通信的基础。以太网交换机是实现数据链路层通信的主要设备,了解以太网交换机的工作原理也是十分必要的。 1、以太网协议…

SQLException: No Suitable Driver Found - 完美解决方法详解

🚨 SQLException: No Suitable Driver Found - 完美解决方法详解 🚨 **🚨 SQLException: No Suitable Driver Found - 完美解决方法详解 🚨****摘要 📝****引言 🎯****正文 📚****1. 问题概述 ❗…

网络层 VII(IP多播、移动IP)【★★★★★★】

一、IP 多播 1. 多播的概念 多播是让源主机一次发送的单个分组可以抵达用一个组地址标识的若干目的主机,即一对多的通信。在互联网上进行的多播,称为 IP 多播(multicast , 以前曾译为组播)。 与单播相比,在一对多的…

【go】内存分配模型

内存是怎么分配给对象的? 内存分配优化的地方是? 讲讲golang内存分配模型? ans: 1.按照对象的大小分配:先算出对象的大小如果是tiny对象,就从tiny block中获取地址和偏移量,将对象打包到mcache;如果是16B以…

Xilinx系FPGA学习笔记(五)ROM的IP核学习

系列文章目录 文章目录 系列文章目录前言ROM IP分布式ROM生成ROM配置创建COE文件 块ROM生成如何快速生成Example Design 两种ROM对比 前言 最近在学习小梅哥的xilinx型FPGA开发板,一边学习一边记录,简化整理一下笔记 ROM IP 在 Memories &Storage …

JVM、JRE和 JDK:理解Java开发的三大核心组件

Java是一门跨平台的编程语言,它的成功离不开背后强大的运行环境与开发工具的支持。在Java的生态中,JVM(Java虚拟机)、JRE(Java运行时环境)和JDK(Java开发工具包)是三个至关重要的核心…

致远个性化之--获取明细表中相同类型的数据汇总,并赋值对应明细行中

需求 由于在近期的项目中,有预算、费用管控等需求,而且在报销填报时,费用明细项可能会有重复相同的费用类型发生多项,而相同的费用类型是多项时,要求按照汇总后的费用管控。 具体示例图如下: 邮寄费发生了两…

有希带你深入理解指针(4)

目录 前言🥰1.回调函数😺1.1回调函数的概念😋 2.qsort使用🤯2.1什么是qsort👻2.2 qsort函数的使用🧐 3.模拟实现qsort😎 前言🥰 本篇文章是对指针知识的进一步讲解,如果…

无人机飞手执照:模拟训练技术详解

随着无人机技术的飞速发展,其在航拍、农业、物流、救援等多个领域的应用日益广泛,对无人机飞手的技能与安全意识要求也随之提高。为了确保无人机操作的安全性与效率,获取无人机飞手执照成为专业从业者不可或缺的步骤。模拟训练作为执照考取过…

第一个搭建SpringBoot项目(连接mysql)

首先新建项目找到Spring Initializr 我使用的URL是https://start.spring.io这里最低的JDK版本是17,而且当网速不好的时候可能会显示超时,这里可以选用阿里云的镜像https://start.aliyun.com可以更快一些但是里面还是有一些区别的 我们这里选择Java语言&a…

【OpenCV3】图像的翻转、图像的旋转、仿射变换之图像平移、仿射变换之获取变换矩阵、透视变换

1 图像的放大与缩小 2 图像的翻转 3 图像的旋转 4 仿射变换之图像平移 5 仿射变换之获取变换矩阵 6 透视变换 1 图像的放大与缩小 resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) src: 要缩放的图片dsize: 缩放之后的图片大小, 元组和列表表示均可.dst: 可选参数, 缩…

AIGC大模型智能抠图(清除背景):Sanster/IOPaint,python(2)

AIGC大模型智能抠图(清除背景):Sanster/IOPaint,python(2) 在文章(1)的基础上,尝试用大模型扣除图中的某些主要景物。 1、首先,安装插件: pip i…

Qt项目使用Inno Setup打包(关于打包中文乱码的解决)

​ 关于打包好的文件乱码解决方法 打包好的文件中文乱码,就是编码格式出现了问题,更改一下中文脚本编码格式,在官网Inno Setup Translations下载好中文脚本 点击下载,然后另存为 得到ChineseSimplified.isl.txt文件后&#…

使用3DUNet训练自己的数据集(pytorch)— 医疗影像分割

代码:lee-zq/3DUNet-Pytorch: 3DUNet implemented with pytorch (github.com) 文章<cicek16miccai.pdf (uni-freiburg.de)3D U-Net: Learning Dense Volumetric Segmentation

贷款利率高低跟什么有关?仅凭身份证就能贷到款?额度是多少?

在金融的广阔舞台上&#xff0c;借款人的“信用基石”——即其综合资质&#xff0c;是决定贷款利率高低的决定性因素。这并非偶然&#xff0c;而是银行基于详尽的风险评估与收益预期所做出的精准判断。 需明确的是&#xff0c;贷款的易得性并不意味着无门槛的放任。它更像是设置…

【动手学深度学习】04 数据操作 + 数据预处理(个人向笔记)

数据操作 N维数组是机器学习和神经网络的主要数据结构其中 2-d 矩阵中每一行表示每一行表示一个样本 当维度来到三维的时候则可以表示成一张图片&#xff0c;再加一维就可以变成多张图片&#xff0c;再加一维则可以变成一个视频 访问元素 冒号表示从冒号左边的元素到冒号右…

巨魔商店2安装教程,支持最新iOS 17.0的所有型号

支持iOS15.0到16.6.1、16.7 RC (20H18)和17.0的所有iPhone/iPad。 工具下载地址&#xff1a; https://wwi.lanzoup.com/b0knd3q5g 密码:czhi Windows安装教程&#xff1a; 1&#xff0c;电脑必须安装ITunes&#xff0c;关闭查找我的 iPhone&#xff0c;手机上必须要有提示&…

python imshow报错怎么解决

实例如下所示&#xff1a; import matplotlib.pyplot as plt plt.imshow(img) #控制台打印出图像对象的信息&#xff0c;而图像没有显示 解决方法&#xff1a; #引入pylab解决 import matplotlib.pyplot as plt import pylab plt.imshow(img) pylab.show()