深度剖析MySQL锁:解开数据库并发控制的神秘面纱

        MySQL 锁是 MySQL 数据库管理系统中为了实现并发控制和数据一致性的机制。在多用户并发访问数据库时,锁可以确保多个事务在对同一数据进行操作时不会相互干扰,以防止数据不一致的现象发生。      

一、锁分类

        MySQL支持多种类型的锁,主要包括全局锁、表锁、行锁、元数据锁、自增长锁等。

        1.1 全局锁

        全局锁顾名思义是对整个数据库加锁,MySQL提供了加全局锁的方法,命令是Flush tables read lock(FTRL),整个库处于只读状态,之后其他线程的以下语句都会被阻塞:数据更新语句、数据定义语句和更新类事务提交语句。全局锁使用场景,做全库备份,不过让全库只读,听上去很危险。

        在 MySQL 中,全局锁是对整个 MySQL 实例的锁定,而非对单个数据库或表的锁定,因此在高并发的生产环境中,除非必要,一般不建议长时间持有全局锁,因为它会严重影响数据库的并发性能。在 InnoDB 存储引擎中,全局锁主要用于 MyISAM 表,而对于 InnoDB 表,通常采用其他机制如行级锁和表级锁来管理并发控制。

        1.2 表级锁

        表级锁,MySQL的表级锁有两种,一种是表锁,一种是元数据锁。

        表锁使用unlock tables主动释放锁,也可以在客户端断开时自动释放。

        元数据锁(MDL)不需要显示的声明,在访问一个表时会自动加上,MDL 的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。

        在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。

        我们可以看到 session A 先启动,这时候会对表 t 加一个 MDL 读锁。由于 session B 需要的也是 MDL 读锁,因此可以正常执行。之后 session C 会被 blocked,是因为 session A 的 MDL 读锁还没有释放,而 session C 需要 MDL 写锁,因此只能被阻塞。

        如果只有 session C 自己被阻塞还没什么关系,但是之后所有要在表 t 上新申请 MDL 读锁的请求也会被 session C 阻塞。前面我们说了,所有对表的增删改查操作都需要先申请 MDL 读锁,就都被锁住,等于这个表现在完全不可读写了。

        如果某个表上的查询语句频繁,而且客户端有重试机制,也就是说超时后会再起一个新 session 再请求的话,这个库的线程很快就会爆满。你现在应该知道了,事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。

        另外 MySQL 支持的 Online DDL 也是通过 MDL 锁来实现的。

        Online DDL 执行流程

  1. MDL 写锁获取:在执行 Online DDL 之初,MySQL会为待修改的表获取 MDL 写锁,这会阻止其他会话对同一张表进行 DDL 操作,同时在最开始阶段也会阻止 DML 操作,确保在结构变更开始时数据的一致性。
  2. 数据拷贝的 DML 降级:根据 DDL 的具体类型,MySQL 可能创建一个临时表或者在原地修改表结构。随后 MDL 写锁会被降级成 MDL 读锁或更低级别的锁,使得在大部分 DDL 执行过程中,对原表的读操作可以继续进行,部分兼容写操作也可以在限定条件下并发执行。
  3. 数据迁移或结构变更:对于In-place DDL(原地数据定义语言操作)操作,MySQL 会创建必要的辅助结构(如临时表空间或Row Log,用于记录DML操作),并在原表数据的基础上进行结构变更。对于 Copy-based DDL(基于拷贝的DDL)操作,MySQL 会创建一个新表结构并将旧表的数据逐步迁移到新表结构中,同时维护一份 Row Log 记录在拷贝过程中发生的 DML 操作。
  4. 并发控制与 Row log 应用:在数据迁移过程中,InnoDB 会使用行级锁和/或间隙锁来保证并发 DML 操作的正确性,并将这些操作记录在 Row Log 中。在 DDL 操作即将完成时,MySQL 会应用 Row Log 中的增量数据,确保所有并发的 DML 操作都被正确地反映在最终的新结构上。
  5. 切换与清理:完成数据迁移后,MySQL 会将旧表替换为新表(如果是copy-based操作)或完成原地结构变更(如果是in-place操作),并在所有 DML 操作均已完成的情况下,解除MDL 锁。
  6. 提交事务与释放锁:最终,整个 DDL 操作被视为一个事务,当所有步骤完成后提交事务,释放 MDL 锁,使得其他会话可以正常执行 DDL 和 DML 操作。

        1.3 行锁

        行锁,存储引擎层由各个引擎实现的,并不是所有的引擎都支持的。行锁就是针对数据表中行记录的锁。在 InnoDB 事务中,行锁是在需要时才加上的,但并不是不需要了就立即释放,而要等到事务结束了才释放。

        知道了这个设定,我们在日常工作中,如果你的事务需要锁多个行,要把最可能造成冲突、最可能影响并发度的锁尽量往后放。

        InnoDB 存储引擎有两种标准的行级锁:

  • 共享锁(S Lock),允许事务读一行数据
  • 排它锁(X Lock),允许事务删除或更新一行数据

        如果一个事务 T1 已经获得了行 r 的共享锁,那么另外的事务 T2 可以立即获得行r的共享锁,因为读取并没有改变行 r 的数据,称这种情况为锁兼容。但若其他的事务 T3 想获取行r的排他锁,则必须等待事务 T1、T2 释放行r的共享锁,这种情况称为锁不兼容。

        1.4 自增长锁

        在 InnoDB 存储引擎的内存结构中,对每个含有自增值的表都有一个自增长计数器。插入操作会依据这个自增长器加1赋值自增长列。这个实现方式称为 AUTO-INC Locking。这种锁其实采用一种特殊的表锁机制,为了提高插入性能,锁不是在一个事务完成后才释放,而是在完成对自增长值插入的 sql 语句后立即释放。

二、锁升级问题

        情况一:不走索引

        MySQL 行锁只能加在索引上如果操作不走索引,就会升级为表锁。因为 InnoDB 的行锁是加在索引上的,如果不走索引,自然就没法使用行锁了,原因是 InnoDB 是将 primary key index 和相关的行数据共同放在 B+ 树的叶节点。InnoDB 一定会有一个 primary key,secondary index 查找的时候,也是通过找到对应的 primary,再找对应的数据行。

        情况二:普通非唯一索引区分度太低

        当非唯一索引上记录数超过一定数量时,行锁也会升级为表锁。测试发现当非唯一索引相同的内容不少于整个表记录的二分之一时会升级为表锁。因为当非唯一索引相同的内容达到整个记录的二分之一时,索引需要的性能比全文检索还要大,查询语句优化时会选择不走索引,造成索引失效,行锁自然就会升级为表锁。

三、MVCC

        MySQL 的多版本并发控制(MVCC, Multi-Version Concurrency Control)是一种为了解决并发读写问题,提高数据库并发性能的机制。在支持 MVCC 的存储引擎中,最典型的是InnoDB。

        3.1 一致性非锁定读

        指 InnoDB 存储引擎通过多版本控制的方式读取当前执行时数据库中的行数据。如果读的时候正在执行delete或update操作,这时读取操作不会因此去等待行上的锁释放。相反的,InnoDB存储引擎会读取行的一个快照数据。

        可以看到,非锁定读机制极大的提高了数据库的并发性。在 InnoDB 存储引擎的默认设置下,这是默认的读取方式,即读取不会占用和等待表上的锁。

        一个行记录可能不止一个快照数据,一般称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control, MVCC)。

        不仅 MySQL,其他数据库都实现了MVCC,只是实现的方式不同,MVCC 没有统一的实现标准。MVCC 避免了加锁操作,开销较低。

        在事务隔离级别 READ COMMITTED 和 REPEATABLE READ 下,InnoDB 存储引擎使用非锁定的一致性读。在 READ COMMITTED 隔离级别下,对于快照,非一致性读总是读取被锁定行的最新一份快照。而在 REPEATABLE READ 隔离级别下,对于快照,非一致性读总是读取事务开始时的行数据版本。

        3.2 一致性锁定读

        有些情况下需要显示的对数据库读取操作进行加锁以保证数据逻辑的一致性。InnoDB 存储引擎对于 select 语句支持两种一致性锁定读操作

  • select ... for update 对读取的行记录加上一个 x 锁,其他事务不能对锁定的行加上任何锁
  • select ... lock in share mode 对读取的行记录加上一个 s 锁,其他事务可以向被锁定的行加 s 锁,但是如果加  x 锁,则会被阻塞。

四、锁的算法实现

        InnoDB 存储引擎有3种行锁的算法

  • Record Lock:单个行记录上的锁,当事务对某一行数据进行修改时,会锁定这一行。
  • Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
  • Next-Key Lock:上边两种锁的结合,锁定一个范围,并且锁定记录本身。

        4.1 幻读解决

        在默认的隔离级别下,InnoDB 存储引擎采用 Next-Key Locking 机制来避免幻读问题。幻读是指在同一事务下,连续两次执行 同样的 sql 语句可能导致不同的结果,第二次 sql 语句可能会返回之前不存在的行。

        假如表t中有1、2、5这三个值的三行记录,会话A执行>2的查询,第一次查询出一条记录,这时会话B插入了一条4的数据,会话A在查询时可能会查到4、5这两条数据造成了幻读。通过Next-Key Locking加锁后会对(2,+∞)这个范围加上x锁,这个时候的插入是不被允许的,从而避免了幻读。

五、死锁

        死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。解决死锁问题最简单的方法时设置超时时间。

        这时事务 A 在等待事务 B 释放 id=2 的行锁,事务 B 在等待事务 A 释放 id=1 的行锁。事务A和事务 B 在互相等待对方释放资源,就进入了死锁状态,当出现死锁后有两种策略:

  • 直接进入等待,直到超时;
  • 发起死锁检测,发现死锁后,主动回滚死锁链条中某一个事务,让其他事务得以正确运行。

        死锁检测是有额外负担的,可以想像一下这个过程:每当一个事务被锁住的时候,就要看看他所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,也就是死锁。

        在实际应用中,合理选择和使用锁机制是优化并发性能和保证数据一致性的关键环节。根据事务的隔离级别和操作需求,MySQL会采取不同的锁策略。

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

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

相关文章

定时器的原理和应用

#include<reg51.h> unsigned char s[]{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; unsigned char count0,num0; void inittimer() {TMOD0x01;//0000 0001TH0(65536-50000)/256; //定时50ms50000us 2562^8 初值向右边移动8位TL0(65536-50000)%256;ET01;//开启定…

多源统一视频融合可视指挥调度平台VMS/smarteye系统概述

系统功能 1. 集成了视频监控典型的常用功能&#xff0c;包括录像&#xff08;本地录像、云端录像&#xff08;录像计划、下载计划-无线导出&#xff09;、远程检索回放&#xff09;、实时预览&#xff08;PTZ云台操控、轮播、多屏操控等&#xff09;、地图-轨迹回放、语音对讲…

windows 下用使用api OCI_ConnectionCreate连接oracle报错 TNS:无法解析指定的连接标识符

背景&#xff0c;两台服务器系统一样&#xff0c;oracle版本一样&#xff0c;其中一台服务器在运行程序的时候报错 TNS:无法解析指定的连接标识符 但是PL/SQL可以正常连接&#xff0c;怀疑是oracle配置文件的原因 tnsnames.ora配置文件大概作用&#xff1a;是Oracle客户端的网…

实时数仓之实时数仓架构(Hudi)

目前比较流行的实时数仓架构有两类&#xff0c;其中一类是以FlinkDoris为核心的实时数仓架构方案&#xff1b;另一类是以湖仓一体架构为核心的实时数仓架构方案。本文针对FlinkHudi湖仓一体架构进行介绍&#xff0c;这套架构的特点是可以基于一套数据完全实现Lambda架构。实时数…

基于 StarRocks 的风控实时特征探索和实践

背景 金融风控特征是在金融领域中用于评估和管理风险的关键指标。它们帮助金融机构识别潜在风险&#xff0c;降低损失&#xff0c;并采取措施规避风险。例如&#xff0c;用户最后一次授信提交时间就是一个重要的金融风控特征。 金融风控实时特征场景是一个典型的大数据实时业务…

【人工智能Ⅱ】实验4:Unet眼底血管图像分割

实验4&#xff1a;Unet眼底血管图像分割 一&#xff1a;实验目的与要求 1&#xff1a;掌握图像分割的含义。 2&#xff1a;掌握利用Unet建立训练模型。 3&#xff1a;掌握使用Unet进行眼底血管图像数据集的分割。 二&#xff1a;实验内容 1&#xff1a;用Unet网络完成眼底血…

基于SpringBoot和Vue的在线视频教育平台的设计与实现

今天要和大家聊的是一款基于SpringBoot和Vue的在线视频教育平台的设计与实现 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&…

STM32时钟简介

1、复位&#xff1a;使时钟恢复原始状态 就是将寄存器状态恢复到复位值 STM32E10xxx支持三种复位形式,分别为系统复位、上电复位和备份区域复位。 复位分类&#xff1a; 1.1系统复位 除了时钟控制器的RCC_CSR寄存器中的复位标志位和备份区域中的寄存器以外,系统 复位将复位…

Redis中的LRU算法分析

LRU算法 概述 Redis作为缓存使用时&#xff0c;一些场景下要考虑内容的空间消耗问题。Redis会删除过期键以释放空间&#xff0c;过期键的删除策略 有两种: 1.惰性删除:每次从键空间中获取键时&#xff0c;都检查取得的键是否过期&#xff0c;如果过期的话&#xff0c;就删除…

【Java面试题】Redis上篇(基础、持久化、底层数据结构)

文章目录 基础1.什么是Redis?2.Redis可以用来干什么&#xff1f;3.Redis的五种基本数据结构&#xff1f;4.Redis为什么这么快&#xff1f;5.什么是I/O多路复用&#xff1f;6.Redis6.0为什么使用了多线程&#xff1f; 持久化7.Redis的持久化方式&#xff1f;区别&#xff1f;8.…

生成式 AI 学习资源大汇总

这里汇聚了该领域的海量学习资源&#xff0c;从研究更新到面试技巧&#xff0c;从课程材料到免费课程&#xff0c;还有实用代码&#xff0c;一应俱全&#xff0c;是你工作流程中的得力助手&#xff01; 前沿研究&#xff1a;每月精心筛选的最佳生成式 AI 论文列表&#xff0c;让…

Linux shell编程学习笔记42:md5sum

0 前言 前几天在国产电脑上遇到一个问题&#xff0c;先后接到两个文件&#xff0c;如何判断这两个文件内容是否相同&#xff1f; 如果是在Windows系统&#xff0c;可以用fc命令&#xff0c;或者用我自己写的FileInfo&#xff0c;提取两个文件有MD5、SHA1、CRC32值进行比较来判…

redis-shake可视化监控

目录 一.redis-shake v4 1.镜像 2.shake.toml 3.启动redis-shake后 二.json-exporter配置 1.Dockerfile 2.config.yml 三.prometheus配置 1.prometheus.yml 2.redis-shake.json 四.grafana 一.redis-shake v4 1.镜像 ######################### Dockerfile #########…

Qt打印系统库的日志 - QLoggingCategory

Qt的动态库通过源码可以可以看到含有大量的qCInfo 和 qCDebug 等大量的日志&#xff0c; 但是我们正常运行Qt程序&#xff0c;这些动态库或插件里面的日志是不会输出到我们的控制台里面的。 所以本章主要记录怎么输出这些日志出来。 一&#xff1a; 步骤 主要使用的是Qt的 函…

Kubernetes中pod的概念

pod pod是什么&#xff1a;pod是k8s中基本的构建模块&#xff0c;一个pod可以包含多个和单个容器&#xff0c;包含多个容器时&#xff0c;这些容器总是运行在同一个工作节点上&#xff0c;因为一个pod绝不会跨多个工作节点。 了解pod&#xff1a; pod将容器绑定在一起&#xf…

【Golang入门教程】Go语言变量的初始化

文章目录 强烈推荐引言举例多个变量同时赋值总结强烈推荐专栏集锦写在最后 强烈推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站:人工智能 推荐一个个人工作&#xff0c;日常中比较常…

政安晨:【Keras机器学习实践要点】(七)—— 使用TensorFlow自定义fit()

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎机器学习 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 在TensorFlow中&#xff0c;fit()是一个非常…

Python+Django+Yolov5路面墙体桥梁裂缝特征检测识别html网页前后端

程序示例精选 PythonDjangoYolov5路面墙体桥梁裂缝特征检测识别html网页前后端 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonDjangoYolov5路面墙体桥梁裂缝特征检测识别html网页前…

Parade Series - SVG Resource

iconfont https://www.iconfont.cn/?spma313x.search_index.i3.2.74e53a819tkkcG音符 <div class"form-group"><a href"Javascript:reload();" class"btn btn-icon btn-outline-light btn-block" style";"><svg t&q…

打造快乐成长的乐园:探索少儿教育项目的魅力

在当今社会&#xff0c;家长们越来越重视孩子的全面发展和个性培养&#xff0c;少儿教育项目因其独特的魅力吸引着越来越多的关注。本文将探讨少儿教育项目的特点、重要性&#xff0c;以及如何打造一个快乐成长的教育乐园。 ### 少儿教育项目的价值 少儿教育项目不仅仅是传授…