Mysql的加锁情况详解

最近在复习mysql的知识点,像索引、优化、主从复制这些很容易就激活了脑海里尘封的知识,但是在mysql锁的这一块真的是忘的一干二净,一点映像都没有,感觉也有点太难理解了,但是还是想把这块给啃下来,于是想通过这篇文章把复盘过程中所有的知识点给记录下来,特别是实操部分

文章目录

  • 一、mysql的锁介绍
    • 共享锁
    • 排他锁
    • 记录锁(Record Locks)
    • 间隙锁
    • 临键锁
  • 二、加锁情况实操
    • 1. 表无显式主键和索引
      • 数据准备
      • 不加任何查询条件的查询
      • 添加条件查询
    • 2. 表有显式主键无索引
      • 数据准备
      • 不带任何条件的查询
      • 通过id查询
    • 3. 表无显式主键有索引
      • 数据准备
      • 不带任何条件的查询
      • 带普通索引ID的查询
      • 带唯一索引的id查询
    • 4.表有显式主键和普通索引
      • 数据准备
      • 不带任何条件的查询
      • where条件是普通索引字段
      • where条件是主键字段
      • where条件同时包含普通索引字段和主键索引字段
    • 5.表有显式主键和唯一索引
      • 数据准备
      • 不带条件查询
      • where条件是唯一索引字段
      • where条件是主键
      • where条件是主键和唯一索引
  • 总结


一、mysql的锁介绍

mysql里有一堆锁,但是会存在一些概念上的交叉,所以这里只列举出常用的,或者说面试中常问的锁进行介绍,如下:

共享锁

共享锁又叫读锁,S锁,加了共享锁的数据还可以被其他事务加共享锁,但是不能被其他事务加排他锁,主要用于保证数据在读取过程中的一致性。可通过lock in share mode显示的给sql加上共享锁

select * from t lock in share mode;

排他锁

排他锁又叫写锁,X锁,加了排他锁的数据不能被其他事务再加排他锁或者共享锁,直到该排他锁被释放;可以通过for update显示的给sql加排他锁,当然,实际工作中不会使用for update,mysql在执行update、insert、delete等DML操作的时候会自动加排他锁;

select * from t for update;

记录锁(Record Locks)

记录锁也可以理解成行锁,作用在索引上,只锁某一行记录

间隙锁

间隙锁锁定的是索引记录锁之间的间隙,或者是索引最小值之前后者最大值之后的间隙,只在RR级别以上被使用;只阻止其他事务插入到间隙中,他们不阻止其他事务在同一个间隙上获得间隙锁

临键锁

临键锁=记录锁+间隙锁

二、加锁情况实操

约定:

  1. 关闭事务自动提交,我们需要在事务里观察加锁情况:set autocommit=0
  2. 使用show engine innodb status\G观察锁的情况
  3. 查看mysql关于锁日志的输出是否打开(默认关闭):show variables like ‘innodb_status_output%’;
  4. 打开开关:set global innodb_status_output_locks=on; set global innodb_status_output=on;
  5. 只演示mysql的默认隔离界别RR下锁的情况,RC隔离级别大部分加的都是行锁
  6. mysql的表一定会有聚簇索引的,有主键使用主键作为聚簇索引,没主键使用唯一且非空列作为聚簇索引,否则使用自己维护的rowid作为聚簇索引
  7. mysql的锁都是加在索引上的

1. 表无显式主键和索引

数据准备

create table t(id int default null,name char(20) default null);
insert into t values(10,'10'),(20,'20'),(30,'30');

不加任何查询条件的查询

  • sql
begin;
select * from t for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    • 表t没有主键没有唯一非空列,所以会创建一条聚簇索引
    • 查询的是全表,没有限制任何条件,所以加的是聚簇索引的临键锁,由于聚簇索引是rowid,所以范围这里我们看不懂
    • 由于没有主键和索引,所以加上条件的查询和不加条件是一样的,这里就不再重复展示了

添加条件查询

  • sql
begin;
select * from t where id = 10 for update;
show engine innodb status\G
  • 图示同上
  • 分析
    • 可以发现,从结果上课与不加条件加锁情况是一致的,都是加的聚簇索引的临键锁;
    • 限制了条件和全表查询一样是因为mysql锁是加在索引上的,并不是加在数据10上的;
    • 不加的话理论上在插入一条id=10的记录也是可以的,这一就出现幻读了

2. 表有显式主键无索引

数据准备

create table t2(id int primary key not null,name char(20) default null);
insert into t2 values(10,'10'),(20,'20'),(30,'30');

不带任何条件的查询

  • sql
begin;
select * from t2 for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    • 结果与1中一样,区别在于这里的id是主键,聚簇索引就是id了,在图里就能显示的看到临建锁的范围了,虽然是16进制的,转换后就是表里对应的10,20,30

通过id查询

  • sql
begin;
select * from t2 where id = 10 for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    • 可以看到,此情况只加了id的记录锁,因为id就是聚簇索引,锁住这一行记录就可以了

3. 表无显式主键有索引

数据准备

create table t3(id int default null,name char(20) default null);
create index idx_id on t3(id);
insert into t3 values(10,'10'),(20,'20'),(30,'30');

不带任何条件的查询

与1.2类似,加的都是聚簇索引的临键锁

带普通索引ID的查询

  • sql
begin;
select * from t3 where id = 10 for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    • 如图,会加聚簇索引的记录所,id的临建锁,id的间隙锁,锁的范围如上图,由此可见我们此时可以插入30之后的数据,不能插入10之前的数据,如下图:
      在这里插入图片描述

带唯一索引的id查询

  • sql
create table t4(id int default null,name char(20) default null);
create unique index idx_id on t4(id);
insert into t4 values(10,'10'),(20,'20'),(30,'30');
begin;
select * from t4 where id = 10 for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    • 因为是唯一索引,且可以为空,所以mysql还会创建聚簇索引,所以此时加的是唯一索引id的记录锁,聚簇索引

4.表有显式主键和普通索引

数据准备

create table t5(id int not null,name char(20) default null,primary key(id),key idx_name(name));
insert into t5 values(10,'10'),(20,'20'),(30,'30');

不带任何条件的查询

  • sql
begin;
select * from t5 for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述

  • 分析

    • 主键id的记录锁(锁表里的每行记录),普通索引name的临键锁

where条件是普通索引字段

  • sql
begin;
select * from t5 where name='10' for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    • 主键id的记录锁(锁id=10一条记录)、普通索引name的临键锁,范围:(-∞,10],普通索引name的间隙锁:(10,20)

where条件是主键字段

  • sql
begin;
select * from t5 where id=10 for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述

  • 分析

    • 查询条件是主键的话就简单了,直接加id的记录锁即可

where条件同时包含普通索引字段和主键索引字段

  • sql
begin;
select * from t5 where id=10 and name='10' for update;
show engine innodb status\G
  • 分析
    • 与单查主键一致,都只是上主键id的记录锁

5.表有显式主键和唯一索引

数据准备

create table t6(id int not null,name char(20) default null,primary key(id),unique key idx_name(name));
insert into t6 values(10,'10'),(20,'20'),(30,'30');

不带条件查询

  • sql
begin;
select * from t6 for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    与普通索引类似,会加主键的记录锁,锁定表里的每条记录,然后加唯一索引的临键锁,范围是:(-∞,10],(10,20],(20,30],(30,10)

where条件是唯一索引字段

  • sql
begin;
select * from t6 where name='10' for update;
show engine innodb status\G
  • 图示
    在这里插入图片描述
  • 分析
    • 两个行锁,分别是主键索引的行锁和唯一索引的行锁

where条件是主键

  • sql
begin;
select * from t6 where id=10 for update;
show engine innodb status\G
  • 分析
    • 只会加主键的行锁

where条件是主键和唯一索引

  • sql
begin;
select * from t6 where id=10 and name='10' for update;
show engine innodb status\G
  • 分析
    • 与只加主键一致,还是只会加主键的行锁;一般涉及到主键的查询都会只锁主键的行锁

总结

至此,mysql加锁的分析就结束了,其实挺绕的,实际总是与自己想的不一致,但是要秉持一个原则,就是mysql的锁除了保证并发事务的情况下对数据的安全读写外,还会用来解决幻读问题;有时候从幻读的角度出发,那么也就理解了为什么会这样加锁了

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

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

相关文章

丹摩征文活动 | AI创新之路,DAMODEL助你一臂之力GPU

目录 前言—— DAMODEL(丹摩智算) 算力服务 直观的感受算力提供商的强大​ 平台功能介绍​ 镜像选择 云磁盘创建 总结 前言—— 只需轻点鼠标,开发者便可拥有属于自己的AI计算王国 - 从丰富的GPU实例选择,到高性能的云磁盘,再到预配置的深度学习…

Linux之日志

日志 在编写网络服务器, 各种软件时, 程序一定要打印一些日志信息. 1. 可以向显示器打印, 也可以向文件中写入. 2. 日志是软件在运行时记录的流水账, 用于排查服务进程挂掉的信息. 其中必须要有的是: 日志等级, 时间, 日志内容.可选的是文件名, 代码行数, 进程pid 等 日志…

IDEA指定Maven的settings不生效问题处理

文章目录 一、问题描述二、问题分析三、问题解决 一、问题描述 在Idea中手动指定了maven的settings配置文件,但是一直没生效。 如下图:设置加载settings-aliyun.xml文件,但是最后发现还是在加载settings.xml文件 二、问题分析 ‌在Intel…

【软考】数据库

1. 数据模型 1.1 概念数据模型 概念数据模型一般用 E-R 图表示,常用术语如下: 实体:客观存在的事物,如:一个单位、一个职工、一个部门、一个项目。属性:学生实体有学号、姓名、出生日期等属性。码&#…

oneplus6线刷、trwp、magisk(apatch)、LSPosed、Shamiko、Hide My Applist

oneplus6线刷android10.0.1 oneplus6线刷包(官方android10.0.1)下载、线刷教程: OnePlus6-brick-enchilada_22_K_52_210716_repack-HOS-10_0_11-zip 启用开发者模式 设置 / 连续点击6次版本号 : 启用开发者模式设置/开发者模式/{打开 usb调试, 打开 网络adb调试,…

ByteBuffer模拟拆包输出消息字符串

以下代码模拟网络编程中的粘包现象,用\n进行分割消息块 源码 public static void main(String[] args) {ByteBuffer byteBuffer1 ByteBuffer.allocate(60) ;byteBuffer1.put("Hello World\nWhat is you name?\nI am Licky!\nHo".getBytes());splice(byt…

成都睿明智科技有限公司怎么样可靠不?

在这个日新月异的数字时代,电商行业如同一股不可阻挡的洪流,席卷着每一个消费者的生活。而抖音,作为短视频与电商完美融合的典范,更是为无数商家开辟了一片全新的蓝海。在这片充满机遇与挑战的海洋中,成都睿明智科技有…

【计算机网络】多路转接之epoll

epoll也是一种linux中的多路转接方案(epoll也是只负责IO过程中的"等") 一、epoll相关接口的使用 1.epoll_create int epoll_create(int size); ​功能:创建一个epoll模型 ① int size:没意义了 >0就行 返回值:返回一个文件…

Linux高阶——1117—TCP客户端服务端

目录 1、sock.h socket常用函数 网络初始化函数 首次响应函数 测试IO处理函数 获取时间函数 总代码 2、sock.c SOCKET() ACCEPT()——服务端使用这个函数等待客户端连接 CONNECT()——客户端使用这个函数连接服务端 BIND()——一般只有服务端使用 LISTEN()——服务端…

【SVN和GIT】版本控制系统详细下载使用教程

文章目录 ** 参考文章一、什么是SVN和GIT二、软件使用介绍1 SVN安装1.1 服务端SVN下载地址1.2 客户端SVN下载地址2 SVN使用2.1 服务端SVN基础使用2.1.1 创建存储库和用户成员2.1.2 为存储库添加访问人员2.2 客户端SVN基础使用2.2.1 在本地下载库中的内容2.2.2 版本文件操作--更…

【含文档】基于django+Vue的荣誉证书管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 主要技术: django,mysql,vue 2.视频演示地址 3.功能 系统定义了三个角色:管理员和学生和教师。 管理员进…

ros2学习日记_241124_ros相关链接

前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…

AIGC-------AIGC在社交媒体内容生成中的应用

AIGC在社交媒体内容生成中的应用 引言 随着人工智能生成内容(AIGC)的快速发展,社交媒体平台上的内容创作方式发生了巨大变化。AIGC使得内容创作的门槛大大降低,从而让更多的人能够参与到社交媒体内容的创作中,同时也使…

GWO-SVMD分解 | Matlab实现GWO-SVMD灰狼算法优化逐次变分模态分解

GWO-SVMD分解 | Matlab实现GWO-SVMD灰狼算法优化逐次变分模态分解 目录 GWO-SVMD分解 | Matlab实现GWO-SVMD灰狼算法优化逐次变分模态分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 GWO-SVMD灰狼算法优化逐次变分模态分解 内有15种用以优化svmd的适应度函数&#…

意识与人工智能:德国语言学家Joscha Bach的“梦境意识”理论探讨

引言 在人类的科学探索中,意识无疑是最深奥的未解之谜之一。尽管我们可以清晰地感知到自己的存在和思维,但意识究竟是什么?它从何而来?是否是物理世界的产物?以及人工智能是否能拥有意识?这些问题一直困扰…

Android Binder技术概览

Android中的Binder是一种基于远程过程调用(Remote Procedure Call, RPC)的轻量级通信机制,核心用于 Android 系统中的进程间通信(Inter-Process Communication, IPC)。Binder 是 Android 系统中不可或缺的一部分&#…

AI模型---安装cuda与cuDNN

1.安装cuda 先打开cmd 输入nvidia-smi 查看显卡支持cuda对应的版本: 然后去英伟达官网下载cuda(外网多刷几次) https://developer.nvidia.com/cuda-toolkit-archive 注意对应版本 安装过程中如果显示如下图: 请安装visual Stu…

ajax (一)

什么是 AJAX [ˈeɪdʒks] ? 概念:AJAX是浏览器与服务器进行 数据通信 的技术,动态数据交互 怎么用AJAX? 1. 先使用 axios [k‘sio ʊ s] 库, 与服务器进行 数据通信 ⚫ 基于 XMLHttpRequest 封装、代码简单、月下载量在 1…

Load-Balanced-Online-OJ(负载均衡式在线OJ)

负载均衡式在线OJ 前言1. 项目介绍2. 所用技术与环境所用技术栈开发环境 3. 项目宏观结构3.1 项目核心模块3.2 项目的宏观结构 4. comm公共模块4.1 日志(log.hpp )4.1.1 日志主要内容4.1.2 日志使用方式4.1.2 日志代码 4.2 工具(util.hpp&…

微信小程序上传微信官方审核流程(1)

1,打开微信开发者工具 2,微信开发者工具右上角有一个上传按钮,点击上传按钮 3,点击完上传按钮会弹出一个上传成功的提示,点击提示框中的确定按钮 4,点击完确定按钮后会显示填写版本好和项目备注 5&#x…