【MySQL】锁机制

文章目录

  • 一、表级锁和行级锁
  • 二、排他锁和共享锁
  • 三、InnoDB行级锁
    • 行级锁
    • 间隙锁
    • 意向共享锁和意向排他锁
  • 四、InnoDB表级锁
  • 五、死锁
  • 六、锁的优化建议


一、表级锁和行级锁

表级锁: 对整张表加锁。开销小,加锁快,不会出现死锁;锁粒度大,发生锁冲突的概率高,并发度低。

行级锁: 对某行记录加锁。开销大,加锁慢,会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度高。


二、排他锁和共享锁

  • 排它锁(Exclusive),又称为X 锁,写锁。
  • 共享锁(Shared),又称为S 锁,读锁。

XS锁之间有以下的关系: SS可以兼容的,XS、SX、XX之间是互斥的

  • 一个事务对数据对象 O 加了 S 锁,可以对 O 进行读取操作但不能进行更新操作。加锁期间其它事务能对O 加 S 锁但不能加 X 锁。

  • 一个事务对数据对象 O 加了 X 锁,就可以对 O 进行读取和更新。加锁期间其它事务不能对 O 加任何锁。

  • 显示加锁:select ... lock in share mode 强制获取共享锁,select ... for update 获取排它锁。

例如:

先创建一张表结构如下:

在这里插入图片描述

在这里插入图片描述

这里事务一 for update 获取了该行记录的排它锁,此时其他事务既不能读也不能写。此时如果事务二想要获取排它锁或共享锁时,也获取不到。

在这里插入图片描述

当然,如果此时事务二想要获取其他行的共享锁或者排它锁时是可以实现的。

在这里插入图片描述

这里我们需要注意的是,在InnoDB中行锁是加在索引上的,如果我们的过滤条件中没有索引,那么就默认加的是表锁。

在这里插入图片描述


三、InnoDB行级锁

行级锁

InnoDB存储引擎支持事务处理,表支持行级锁定,并发能力更好。

  1. InnoDB行锁是通过给索引上的索引项加锁来实现的,而不是给表的行记录加锁实现的,这就意味着只有通过索引条件检索数据,InnoDB才使用行级锁,否则InnoDB将使用表锁。

举一个例子,还是上面的 user 表,我们将 name 一列创建上一个普通索引。

在这里插入图片描述

这里我们可以看到,如果给name一列添加索引时,那么InnoDB就会使用行级锁。

  1. 由于InnoDB的行锁实现是针对索引字段添加的锁,不是针对行记录加的锁,因此虽然访问的是InnoDB引擎下表的不同行,但是如果使用相同的索引字段作为过滤条件,依然会发生锁冲突,只能串行进行,不能并发进行。

在这里插入图片描述

  1. 即使SQL中使用了索引,但是经过MySQL的优化器后,如果认为全表扫描比使用索引效率更高,此时会放弃使用索引,因此也不会使用行锁,而是使用表锁,比如对一些很小的表,MySQL就不会去使用索引。

在串行化隔离级别中解决了脏读、不可重复读和幻读的问题,因为了在串行化中纯粹使用了共享锁和排它锁。

在这里插入图片描述

这说明了SS锁是可以共享的,SX锁是互斥的。

在这里插入图片描述

如果事务1通过主键索引对一行记录加锁,那么事务2如果通过辅助索引也锁定了和事务1一样的行,那么事务2将不能加锁。

在这里插入图片描述

行锁是给索引加的锁,而不是给数据加的锁。


间隙锁

串行化隔离级别是如何解决幻读问题的?

幻读问题

💕 范围查询

在这里插入图片描述

本质上是通过 间隙锁(gap lock) 解决的。

我们先来看现象:

在这里插入图片描述

下面我们来解决一下原因:

在这里插入图片描述

所以,当事务一向间隙中插入数据时,就会阻塞到间隙锁上面。

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做 “间隙(GAP)”,InnoDB 也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。举例来说, 假如 user 表中只有 101 条记录, 其 userid 的值分别是 1,2,…,100,101, 下面的 SQL:

select * from user where userid > 100 for update;

是一个范围条件的检索,InnoDB 不仅会对符合条件的 userid 值为 101 的记录加锁,也会对userid 大于 101(但是这些记录并不存在)的"间隙"加锁,防止其它事务在表的末尾增加数据。

InnoDB使用间隙锁的目的,为了防止幻读,以满足串行化隔离级别的要求,对于上面的例子,要是不使用间隙锁,如果其他事务插入了 userid 大于 100 的任何记录,那么本事务如果再次执行上述语句,就会发生幻读。

间隙锁的加锁范围

现象一:

在这里插入图片描述

原因:

在这里插入图片描述

现象二:

在这里插入图片描述

我们可以看到与预期的现象不同, 这是什么原因呢?

在这里插入图片描述

其实这是因为事务在查询时,如果发现索引查询和整表查询所得到的行数相差不多时,MySQL就优化查询方式,将索引查询优化为整表查询,这会导致在加锁时直接加的是 表级锁, 对整张表加锁会导致插入任何数据都会阻塞。

所以,对于间隙锁的加锁范围,我们应该视情况而定。


💕 等值查询

现象:

在这里插入图片描述

原因:

在这里插入图片描述

因此,串行化隔离在面对等值查询时,也可以通过间隙锁来很好的避免幻读问题。


意向共享锁和意向排他锁

首先我们来看一个问题:如果我们想要获取一张表的表锁时,首先得知道这张表有没有被其他事务获取过锁?因为这张表中可能有其他事务的行级锁!

当我们想要获取一张表的共享锁S或者排它锁X时,最起码得确定,这张表又没有被其他事务获取过X锁!

假如这张表的数据非常大(一千万行数据),那么我们应该如何从中得知它有没有被其他事务获取过行锁X锁呢?

这里我们就可以使用意向锁来解决这里的效率问题了。

  • 意向共享锁(IS锁):事务计划给记录加行共享锁,事务在给一行记录加共享锁前,必须先取得该表的IS 锁。
  • 意向排他锁(IX锁):事务计划给记录加行排他锁,事务在给一行记录加排他锁前,必须先取得该表的IX 锁。

在这里插入图片描述

说明一下:

  1. 意向锁是由InnoDB存储引擎获取行锁之前自己获取的
  2. 意向锁之间都是兼容的,不会产生冲突
  3. 意向锁存在的意义是为了更高效的获取表锁(表格中的X和S指的是表锁,不是行锁!!!)
  4. 意向锁是表级锁,协调表锁和行锁的共存关系。主要目的是显示事务正在锁定某行或者试图锁定某行

因此,要解决上面所说的效率问题,当我们要获取表的X锁时,不需要再检查表中的哪些行锁(X或者S)占用,只需要快速检查IX和IS锁即可。


四、InnoDB表级锁

在绝大部分情况下都应该使用行锁,因为事务和行锁往往是选择InnoDB的理由,但个别情况下也使用表级锁:

  1. 事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间等待和锁冲突;
  2. 事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。
    如:
    LOCK TABLE user READ;读锁锁表
    LOCK TABLE user WRITE; 写锁锁表
    事务执行…
    COMMIT/ROLLBACK; 事务提交或者回滚
    UNLOCK TABLES; 本身自带提交事务,释放线程占用的所有表锁

五、死锁

MyISAM 表锁是 deadlock free 的, 这是因为 MyISAM 总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但在 InnoDB 中,除单个 SQL 组成的事务外,锁是逐步获得的,即锁的粒度比较小,这就决定了在 InnoDB 中发生死锁是可能的,如下:

在这里插入图片描述

当然,mysql server 检测到死锁发生时,会自动进行事务的回滚操作。从而避免死锁的发生。

死锁问题一般都是我们自己的应用造成的,和多线程编程的死锁情况相似,大部分都是由于我们多个线程在获取多个锁资源的时候,获取的顺序不同而导致的死锁问题。因此我们应用在对数据库的多个表做更新的时候,不同的代码段,应对这些表按相同的顺序进行更新操作,以防止锁冲突导致死锁问题。


六、锁的优化建议

  1. 尽量使用较低的隔离级别
  2. 设计合理的索引并尽量使用索引访问数据,使加锁更加准确,减少锁冲突的机会提高并发能力
  3. 选择合理的事务大小,小事务发生锁冲突的概率小
  4. 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会
  5. 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响
  6. 不要申请超过实际需要的锁级别
  7. 除非必须,查询时不要显示加锁

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

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

相关文章

STL-list的使用简介

目录 ​编辑 一、list的底层实现是带头双向循环链表 二、list的使用 1、4种构造函数(与vector类似)​编辑 2、迭代器iterator 3、容量(capicity)操作 4、element access 元素获取 5、增删查改 list modifiers 6、list的迭…

Linxu每日智囊

每日分享三个Linux命令,悄悄培养读者的Linux技能。 欢迎关注公众号(NLP Research) apt 作用 包管理器 语法 apt [选项] 软件包 参数: -h:帮助-y:当安装过程提示选择全部为"yes"-q:不显示安装的过程案例 列出所有可更新的软件清单命令sudo apt update升级软…

ROS2——Parameters

节点可以使用参数来配置各项操作,这些参数可以说布尔值、整数、字符串等类型。节点在启动时会读取参数。我们将参数单独列出来,而不是写在源文件中,这样做可以方便我们调试,因为在不同的机器人、环境中,我们需要的参数…

【Unity】Joystick Pack摇杆插件实现锁四向操作

Joystick Pack ​ 简介:一款Unity摇杆插件,非常轻量化 ​ 摇杆移动类型:圆形、横向、竖向 ​ 摇杆类型: Joystick描述Fixed固定位置Floating浮动操纵杆从用户触碰的地方开始,一直固定到触碰被释放。Dynamic动态操纵…

网卡高级设置-提高网络环境

网卡高级设置,提高网络质量排除一些连接问题 一、有线网卡 1、关闭IPv6; 可以关闭协议版本6,因为它会引起一些网络连接问题,而且现在几乎用不到IP6。 2、关闭节约电源模式; 右击计算机->设备->设备管理器-&…

开源C语言库Melon:数据恢复算法

本文讲述开源C语言库Melon中的里德所罗门纠错码的使用。 关于 Melon 库,这是一个开源的 C 语言库,它具有:开箱即用、无第三方依赖、安装部署简单、中英文文档齐全等优势。 Github repo 简介 里德所罗门编码是一种纠错码技术,…

微信小程序的生命周期函数有哪些?

面试官:说说微信小程序的生命周期函数有哪些? 一、是什么 跟vue、react框架一样,微信小程序框架也存在生命周期,实质也是一堆会在特定时期执行的函数 小程序中,生命周期主要分成了三部分: 应用的生命周期…

MacOS安装Miniforge、Tensorflow、Jupyter Lab等(2024年最新)

大家好,我是邵奈一,一个不务正业的程序猿、正儿八经的斜杠青年。 1、世人称我为:被代码耽误的诗人、没天赋的书法家、五音不全的歌手、专业跑龙套演员、不合格的运动员… 2、这几年,我整理了很多IT技术相关的教程给大家&#xff0…

MySQL数据库导入导出远程备份

一 navcat导入导出 导入 选择数据库 选择自己需要的的脚本进行导入 18万的sql脚本数据 导入时间33秒左右 导出 选择表右击----转存SQL文件---结构和数据 导出时间比较快 二 mysqldump 导入导出 先进入mysql的安装bin目录下,先将所要导入的脚本放入该bin目录下…

从优化设计到智能制造:生成式AI在可持续性3D打印中的潜力和应用

可持续性是现代工业中一个紧迫的问题,包括 3D 打印领域。为了满足环保制造实践日益增长的需求,3D 打印已成为一种有前景的解决方案。然而,要使 3D 打印更具可持续性,还存在一些需要解决的挑战。生成式人工智能作为一股强大的力量&…

Java虚拟机类加载机制探究:生命周期、初始化、使用与验证

一、java虚拟机与程序的生命周期 在如下几种情况之下,java虚拟机将结束生命周期: 执行了System.exit()方法程序正常执行结束程序在执行过程中遇到了异常或者错误而异常终止由于操作系统用出现错误而导致java虚拟机进程终止 二、类的加载,链…

基于ssm运动会管理系统的设计与实现 【附源码】

基于ssm运动会管理系统的设计与实现 【附源码】 🍅 作者主页 央顺技术团队 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 文末获取源码联系方式 📝 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuil…

CSS 圆形分割按钮动画 带背景、图片

<template><view class="main"><view class="up"> <!-- 主要部分上 --><button class="card1"><image class="imgA" src="../../static/A.png"></image></button><butt…

NIO通信代码示例

NIO通信架构图 1.Client NioClient package nio;import constant.Constant;import java.io.IOException; import java.util.Scanner;public class NioClient {private static NioClientHandle nioClientHandle;public static void start() {nioClientHandle new NioClientHa…

3 快速前端开发

3 前端JavaScript 3 前端JavaScript1. JavaScript1.1 代码位置1.2 注释1.3 变量1.4 字符串类型案例&#xff1a;跑马灯 1.5 数组案例&#xff1a;动态数据 1.6 对象&#xff08;字典&#xff09;案例&#xff1a;动态表格 1.7 条件语句1.8 函数 2.DOM2.1 事件的绑定 3.知识点的…

redis中的string相关的部分命令

redis命令手册 redis中文官网查看文档 挨个进行输出调试 Redis Setnx 命令 Redis Getrange 命令 Redis Mset 命令 redis 127.0.0.1:6379> MSET key1 "Hello" key2 "World" OK redis 127.0.0.1:6379> GET key1 "Hello" redis 127.0.0.1:…

LLVM的安装步骤实战

目录 1. 准备环境 1.1 安装必备软件包 1.2 配置Git 2. 用CMake构建 2.1 克隆代码库 2.2 创建构建目录 2.3 生成构建系统文件 3. 自定义构建 3.1 CMake定义的变量 3.2 LLVM定义的变量 4. 总结 1. 准备环境 首先操作系统可以是Linux、FreeBSD、macOS或Windows。 同…

2.【CPP】入门(宏||内联函数||拷贝构造||析构函数||构造函数)

0x01.引言 1.实现一个宏函数ADD #define ADD(x,y) ((x)(y))//宏是预编译阶段完成替换&#xff0c;注意括号2.宏的优缺点 优点&#xff1a; 1.增强代码的复用性 2.宏函数不用建立栈帧&#xff0c;提高性能 缺点&#xff1a; 1.不方便调试 2.没有安全检查 0x02.内联函数 1.以空…

可狱可囚的爬虫系列课程 11:Requests中的SSL

一、SSL 证书 SSL 证书是数字证书的一种&#xff0c;类似于驾驶证、护照、营业执照等的电子副本。SSL 证书也称为 SSL 服务器证书&#xff0c;因为它是配置在服务器上。 SSL 证书是由受信任的数字证书颁发机构 CA 在验证服务器身份后颁发的&#xff0c;其具有服务器身份验证和…

base64与BytesIO图片进行编码、解码;api调用

base64与BytesIO简单介绍 io.BytesIO 和 Base64 编码都是用于在内存中处理二进制数据的方法&#xff0c;但它们的目的和使用场景有所不同。 1&#xff09; io.BytesIO io.BytesIO 是 Python io 库中的一个类&#xff0c;它提供了一个在内存中处理二进制数据的接口&#xff0…