64 mysql 的 表锁
前言
我们这里来说的就是 我们在 mysql 这边常见的 几种锁
行共享锁, 行排他锁, 表意向共享锁, 表意向排他锁, 表共享锁, 表排他锁
我们前面了解了行共享锁, 行排他锁, 表意向共享锁, 表意向排他锁 等等相关
我们这里 来看一下 表共享锁, 表排他锁 的获取, 以及 和 其他表级别锁的冲突的处理
需要设置 auto_commit 为 0, 否则不会走 表锁 的相关业务流程
表排他锁
我们这里调试 sql 如下 这里会先获取 t_user_02 的表排他锁, 然后再释放掉
begin;
lock tables t_user_02 write;
unlock tables;
commit;
我们这里重点关注 “lock tables t_user_02 write;” 的执行流程

表锁 mysql层 到 innodb引擎层 的适配是这里的 handler.cc 中进行适配的
到下图断点这里是 innodb 的处理, 验证了 lock 命令, autocommit 为 false 以及一些其他的条件, 然后 row_lock_table_for_mysql 是整体的获取表锁的业务流程, 诸如 获取到锁之后继续往下走, 没有获取到锁之后 wait, 重试 等等

这里就是获取表锁的宏观流程了, 如果获取到了 则直接返回
如果没有获取到, 则挂起当前线程, 等待唤醒, 唤醒之后 进行重试

获取表锁的具体实现如下, 和之前的获取 表意向共享锁, 表意向排他锁 的情况类似
我们这里重点看一下 表级别锁的兼容机制, 这是影响到能否获取到锁的关键

我们这里将问题简单化, 暂时不考虑 matrix 中的 自增长锁 的处理
表意向锁 和 表意向锁 之间是相互兼容的
表意向锁 和 表锁 之间兼容如下, 表意向共享锁 和 表共享锁 兼容, 其他的三种情况互不兼容
表锁 和 表锁 之间的兼容如下, 表共享锁 和 表共享锁 兼容, 其他的三种情况互不兼容
对于我们这里 获取表排他锁的场景下面, 只有无锁状态, 我们可以获取成功, 但凡有 其他事务持有 表意向共享/排他锁, 表共享/排他锁 当前事务的获取 表排他锁 都会失败
对于获取 表共享锁 的场景下面, 只有无锁状态, 其他事务获取了表意向共享锁 或者 表共享锁 的情况下面, 我们可以获取锁成功, 但凡有其他事务持有 表意向排他锁, 表排他锁, 当前事务的获取 表共享锁 都会失败

表共享锁
我们这里调试 sql 如下 这里会先获取 t_user_02 的表共享锁, 然后再释放掉
begin;
lock tables t_user_02 read;
unlock tables;
commit;
这里的获取 表共享锁 的流程和前面 获取 表排他锁 的流程一样, 只是 锁的兼容有一些 差异

我们这里将问题简单化, 暂时不考虑 matrix 中的 自增长锁 的处理
表意向锁 和 表意向锁 之间是相互兼容的
表意向锁 和 表锁 之间兼容如下, 表意向共享锁 和 表共享锁 兼容, 其他的三种情况互不兼容
表锁 和 表锁 之间的兼容如下, 表共享锁 和 表共享锁 兼容, 其他的三种情况互不兼容
对于我们这里 获取表共享锁的场景下面, 只有无锁状态, 其他事务获取了表意向共享锁 或者 表共享锁 的情况下面, 我们可以获取锁成功, 但凡有其他事务持有 表意向排他锁, 表排他锁, 当前事务的获取 表共享锁 都会失败
对于 获取表排他锁的场景下面, 只有无锁状态, 我们可以获取成功, 但凡有 其他事务持有 表意向共享/排他锁, 表共享/排他锁 当前事务的获取 表排他锁 都会失败

表排他锁阻塞的 N 种方式
表意向排他锁 和 表排他锁 的阻塞方式基本上是一样的, 这里不多赘述
假设我们这里尝试模拟 各种阻塞的方式, 事务1先进行执行, 然后事务2尝试获取表排他锁, 产生阻塞
但是这些阻塞 是还没有到获取表锁 之前的目标表的 MDL元数据锁的阻塞
事务2 这边执行固定的 sql 语句如下
begin;
lock tables t_user_02 write;
unlock tables;
commit;
事务1获取 表意向共享锁 导致 事务2 获取MDL元数据锁 阻塞
begin;
select * from t_user_02 where id = '1' lock in share mode;
-- sleep 10min
commit;
事务1获取 表意向排他锁 导致 事务2获取MDL元数据锁 阻塞
begin;
select * from t_user_02 where id = '1' for update;
-- sleep 10min
commit;
事务1获取 表共享锁锁 导致 事务2获取MDL元数据锁 阻塞
begin;
lock tables t_user_02 read;
-- sleep 10min
unlock tables;
commit;
事务1获取 表排他锁锁 导致 事务2获取MDL元数据锁 阻塞
begin;
lock tables t_user_02 write;
-- sleep 10min
unlock tables;
commit;
表共享锁阻塞的 N 种方式
假设我们这里尝试模拟 各种阻塞的方式, 事务1先进行执行, 然后事务2尝试获取表共享锁, 产生阻塞
但是这些阻塞 是还没有到获取表锁 之前的目标表的 MDL 元数据锁的阻塞
事务2 这边执行固定的 sql 语句如下
begin;
lock tables t_user_02 read;
unlock tables;
commit;
事务1获取 表意向排他锁 导致 事务2获取MDL元数据锁 阻塞
begin;
select * from t_user_02 where id = '1' for update;
-- sleep 10min
commit;
事务1获取 表排他锁锁 导致 事务2获取MDL元数据锁 阻塞
begin;
lock tables t_user_02 write;
-- sleep 10min
unlock tables;
commit;
表锁的 阻塞 和 唤醒
假设我们这边 事务1 执行 sql 如下
begin;
select * from t_user_02 where id = '2' for update;
-- sleep 10min
commit;
事务2 执行 sql 如下, 然后到 “select * from t_user_02 where id = '2' for update;
” 的时候, 事务会阻塞, 然后 之后手动 commit 事务1, 可以看到 唤醒的流程
begin;
select * from t_user_02 where id = '2' for update;
-- sleep 10min
commit;
这个就是通过线程的相关 api 进行 wait 和 notify 了
wait 这边这边主要是基于 pthread_cond_wait 来进行线程的挂起处理

手动 commit 事务1, thr 是目标锁 等待队列中取出的一个待唤醒的线程
然后设置会 设置 pthread_cond_wait 中的等待的条件, 以达到唤醒目标线程的效果

来到目标线程这边, 目标线程 被唤醒了, 然后继续走后面的流程

行锁, 表锁, 元数据锁 的查看
行锁的阻塞信息, 可以再 INNODB_LOCKS, INNODB_LOCK_WAITS 中查看
select * from information_schema.INNODB_LOCKS;
select * from information_schema.INNODB_LOCK_WAITS;
构造一个 事务1 获取 id 为 2 的记录的行共享锁, 事务2 获取 id 为 2 的记录的行排他锁, 造成的阻塞
从这里可以看到 两个事务尝试获取 t_user_02 表的 第3条 记录, 一个获取行共享锁, 一个获取行排他锁
结合等待信息来看, 可以看出的是 获取 行排他锁 的事务在等待 持有 行共享锁 的事务


show processlist 可以看到等待的线程, 以及阻塞的 sql
工作线程一般是靠后面的线程, 可以推断出 持有锁的线程是 30号, 阻塞的是 31号 线程

表锁的阻塞信息, 可以通过如下命令来查看
show open tables where in_use > 0;
执行结果如下, 可以推断的是 t_user_02 的表锁被一个事务持有, 具体的是读锁还是写锁分辨不出来, 只能通过 实际的业务锁获取来判断
如果业务这边获取的是读锁, 则表示持有的是写锁, 如果业务这边获取的是写锁, 则判断不了持有的是读锁还是写锁

show processlist 可以看到等待的线程, 以及阻塞的 sql
工作线程一般是靠后面的线程, 可以推断出 持有锁的线程是 30号, 阻塞的是 31号 线程

元数据锁 这边一般只有通过 show processlist 中可以看出了 或者 mysql 服务器的堆栈信息
比如如上 表锁的例子
元数据锁在大多数的命令都会获取, 但是生命周期不太一样
比如 “lock tables t_user_02 read/write;” 类型的指令, 是先获取 表的元数据锁, 然后再执行业务处理, 再释放 表的元数据锁
比如 “select * from t_user_02 where id = '2' for update;” 类型的指令, 是先获取 表的元数据锁, 然后释放 表的元数据锁, 最后再执行业务处理
因此 构造元数据锁阻塞的方式可以由 事务1 获取表锁, 事务2 获取表锁, 或者行锁都会阻塞, 事务2 阻塞是阻塞在获取 表元数据锁 的地方

完
相关文章:
64 mysql 的 表锁
前言 我们这里来说的就是 我们在 mysql 这边常见的 几种锁 行共享锁, 行排他锁, 表意向共享锁, 表意向排他锁, 表共享锁, 表排他锁 我们前面了解了行共享锁, 行排他锁, 表意向共享锁, 表意向排他锁 等等相关 我们这里 来看一下 表共享锁, 表排他锁 的获取, 以及 和 其他表级…...
【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】题库(1)
前言 大家好吖,欢迎来到 YY 滴计算机网络 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 本博客主要内容,收纳了一部门基本的计算机网络题目,供yy应对期中考试复习。大家可以参考 欢迎订阅 YY滴其他专栏!…...
ajax关于axios库的运用小案例
AJAX案例 图书管理 四大功能: 展示图书删除图书编辑图书信息新增图书 步骤 1.bootstrap弹窗来实现新增和编辑图书时出现的弹窗 有两种方案: a.可以用自带的属性来进行弹窗的显示和隐藏 b.可以通过JS进行控制,此操作可以进行自定义&am…...
微搭低代码入门01变量
目录 1 变量的定义2 变量的赋值3 变量的类型4 算术运算符5 字符串的连接6 模板字符串7 检查变量的类型8 解构赋值8.1 数组的解构赋值8.2 对象的解构赋值 9 类型转换9.1 转换为字符串9.2 转换为数字9.3 转换为布尔值 总结 好些零基础的同学,在使用低代码的时候&#…...
盘点2024年10款视频剪辑,哪款值得pick!!
在这个短视频盛行的时代,如何让我们的故事更生动有趣呢?那就要对短视频进行修饰了。这就需要借助视频剪辑工具:而一款好的工具不仅仅是视频的“美颜”,更是创意的灵魂所在!想象一下,运用一款功能齐全的剪辑…...
苹果手机照片批量删除:一键清理,释放空间
在数字化时代,iPhone不仅是我们沟通的桥梁,也是记录生活的重要工具。然而,随着时间的积累,手机中的照片数量不断增加,不仅占用大量存储空间,也让设备变得缓慢。苹果手机照片批量删除成为了一个普遍的需求。…...
《AI 大模型:重塑软件开发新生态》
《AI 大模型:重塑软件开发新生态》 一、AI 大模型引领软件开发新潮流二、AI 大模型在软件开发中的优势(一)提高开发效率(二)减少错误与提升质量(三)激发创新与拓展功能 三、AI 大模型在软件开发…...
uniapp(API-Promise 化)
一、异步的方法,如果不传入 success、fail、complete 等 callback 参数,将以 Promise 返回数据异步的方法,且有返回对象,如果希望获取返回对象,必须至少传入一项 success、fail、complete 等 callback 参数,…...
【考研数学 - 数二题型】考研数学必吃榜(数二)
数学二 suhan, 2024.10 文章目录 数学二一、函数❗1.极限1.1求常见极限1.2求数列极限1.2.1 n项和数列极限1.2.2 n项连乘数列极限1.2.3 递推关系定义的数列极限 1.3确定极限式中的参数1.4无穷小量阶的比较 2.连续2.1判断是否连续,不连续则判断间断点类型2.2证明题 二…...
Redis生产问题(缓存穿透、击穿、雪崩)——针对实习面试
目录 Redis生产问题什么是缓存穿透?如何解决缓存穿透?什么是缓存击穿?如何解决缓存击穿?缓存穿透和缓存击穿有什么区别?什么是缓存雪崩?如何解决缓存雪崩? Redis生产问题 什么是缓存穿透&#x…...
android openGL中模板测试、深度测试功能的先后顺序
目录 一、顺序 二、模板测试 1、概念 2、工作原理 3、关键函数 三、深度测试 1、概念 2、工作原理 3、关键函数 三、模板测试和深度测试的先后顺序 一、顺序 在Android OpenGL中,模板测试(Stencil Testing)是在深度测试࿰…...
CCF PTA 编程培训师资认证2021年7月真题- C++兑换礼品
【题目描述】 小零和小壹是两个爱玩游戏的小孩,他俩平时最擅长的是解谜游戏,可今天 遇到了一个有点难的算法问题,希望能得到你的帮助。 他们面对的是一个电子装置,正面有 n 个排成一列的按钮,按钮上贴着编号 1~n 号的…...
火山引擎云服务docker 安装
安装 Docker 登录云服务器。 执行以下命令,添加 yum 源。 yum update -y yum install epel-release -y yum clean all yum list依次执行以下命令,添加Docker CE镜像源。更多操作请参考Docker CE镜像。 # 安装必要的一些系统工具 sudo yum install -y yu…...
【taro react】 ---- 常用自定义 React Hooks 的实现【六】之类渐入动画效果的轮播
1. 效果 2. 场景 css 效果实现:可以看到效果图中就是一个图片从小到大的切换动画效果,这个效果很简单,使用 css 的 transform 的 scale 来实现图片的从小到大的效果,切换就更加简单了,不管是 opacity 还是 visibility 都可以实现图片的隐藏和显示的切换。React.Children.m…...
基础算法练习--滑动窗口(已完结)
算法介绍 滑动窗口算法来自tcp协议的一种特性,它的高效使得其也变成了算法题的一种重要考点.滑动窗口的实现实际上也是通过两个指针前后遍历集合实现,但是因为它有固定的解题格式,我将其单独做成一个篇章. 滑动窗口的解题格式: 首先,定义两个指针left和right,与双指针不同的…...
深度学习经典模型之ZFNet
1 ZFNet 1.1 模型介绍 ZFNet是由 M a t t h e w Matthew Matthew D . Z e i l e r D. Zeiler D.Zeiler和 R o b Rob Rob F e r g u s Fergus Fergus在AlexNet基础上提出的大型卷积网络,在2013年ILSVRC图像分类竞赛中以11.19%的错误率获得冠军(实际…...
Linux系统-ubuntu系统安装
作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 这是Linux进阶部分的最后一大章。讲完这一章以后,我们Linux进阶部分讲完以后,我们的Linux操作部分就…...
2-Ubuntu/Windows系统启动盘制作
学习目标: 掌握使用Win32DiskImager、Rufus等工具制作系统启动盘的基本步骤。独立将ISO镜像文件写入USB闪存驱动器,确保在需要时顺利安装或修复系统。通过学习如何选择正确的源文件和目标驱动器,理解启动盘的使用场景和注意事项,…...
你使用过哪些MySQL中复杂且使用不频繁的函数?
在MySQL中,除了常用的SELECT、INSERT、UPDATE等基本操作外,还有许多复杂且功能强大的函数,它们能够处理各种复杂的数据处理需求。这些函数虽然在日常开发中可能不常使用,但在特定场景下却能够发挥巨大的作用。下面,我将…...
Redis-07 Redis哨兵
操作实现 此处应该6台虚拟机,其中3台是哨兵,但因为内存限制没有那么多 1.将sentinel文件拷贝到/myredis目录下 2.sentinel.conf文件重要参数 新建配置文件sentinel26379.conf sentinel26380.conf sentinel26381.conf bind 0.0.0.0 daemonize yes pr…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
