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

news2024/11/24 23:14:13

        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.coloradmin.cn/o/1553690.html

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

相关文章

DataX-Oracle新增writeMode支持update

目录 前言 第一步下载源码 第二步修改源码 1、Oraclewriter 2、WriterUtil 2.1、修改getWriteTemplate方法 2.2、新增onMergeIntoDoString与getStrings方法 3、CommonRdbmsWriter 3.1、修改startWriteWithConnection 3.2、修改doBatchInsert 3.3、修改fillPreparedStatem…

苹果应用商店上架利器:推荐几款常用的应用发布工具

摘要 移动应用app上架是开发者关注的重要环节,但常常会面临审核不通过等问题。为帮助开发者顺利完成上架工作,各种辅助工具应运而生。本文探讨移动应用app上架原理、常见辅助工具功能及其作用,最终指出合理使用工具的重要性。 引言 移动应…

洛谷_P1803 凌乱的yyy / 线段覆盖_python写法

P1803 凌乱的yyy / 线段覆盖 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 这道题是不是用python做只能做到70分啊?? n int(input()) data [] for i in range(n):data.append(list(map(int,input().split())))data.sort(keylambda x:x[1])ans 1 mi…

Solidity Uniswap V2 Router swapTokensForExactTokens

最初的router合约实现了许多不同的交换方式。我们不会实现所有的方式,但我想向大家展示如何实现倒置交换:用未知量的输入Token交换精确量的输出代币。这是一个有趣的用例,可能并不常用,但仍有可能实现。 GitHub - XuHugo/solidit…

景联文科技高质量大模型训练数据汇总!

3月25日,2024年中国发展高层论坛年会上,国家数据局局长刘烈宏在“释放数据要素价值,助力可持续发展”的演讲中表示,中国10亿参数规模以上的大模型数量已超100个。 当前,国内AI大模型发展仍面临诸多困境。其中&#xff…

批量剪辑视频,批量调整片头片尾时长,批量剪辑更高效!

在视频剪辑的世界里,有时候我们需要对视频的片头片尾进行精细调整,以适应不同的需求和创意。然而,传统的视频剪辑软件往往操作繁琐,效率低下,让人望而却步。今天,我要为您介绍一种全新的批量剪辑方式&#…

一个传入省市区ID的级联框

省市区ID 功能edit页面(主要)script逻辑如何拿到当前级联下所有ID数组长ID数组是如何回显的 (1)长ID数组是如何回显的 (2) 功能 选择第一层传第一层下的所有 id 数组,选择第二层传递第二层以及第二层下的所有 id 数组 edit页面(主要) 编辑页的一个 Table&#xff0c…

Dynamo设置按链接视图显示

Hello大家好!我是九哥~ 先来看一段视频: Dynamo设置链接视图 相信用Revit的小伙伴都用到过这个功能,就是在链接Revit模型时,为了便于出图,我们经常需要将链接模型从“按主体视图”改为“按链接视图”,这样能…

buy me a btc 使用数字货币进行打赏赞助

最近在调研使用加密货币打赏的平台,发现idatariver平台 https://idatariver.com 推出的buymeabtc功能刚好符合使用场景,下图为平台的演示项目, 演示项目入口 https://buymeabtc.com/idatariver 特点 不少人都听说过buymeacoffee,可以在上面发…

BabySQL【2019极客大挑战】

知识点: 功能分析 登录界面一般是 where username and password 可以从username出手,注释掉and语句单引号闭合绕过 通过测试和报错信息发现是一个单引号读取输入可以单引号闭合绕过关键字过滤 or and 过滤 || &&替换双写绕过select from wher…

【学习笔记】java项目—苍穹外卖day01

文章目录 苍穹外卖-day01课程内容1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 苍穹外卖项目介绍2.1 项目介绍2.2 产品原型2.3 技术选型 3. 开发环境搭建3.1 前端环境搭建3.2 后端环境搭建3.2.1 熟悉项目结构3.2.2 Git版本控制3.2.3 数据库环境搭建3.2.4 前…

基于单片机环境监测温湿度PM2.5系统设计

**单片机设计介绍,基于单片机环境监测温湿度PM2.5系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机环境监测温湿度PM2.5系统是一个集成了传感器技术、单片机控制以及数据处理与显示功能的综合性系统…

30-3 越权漏洞 - 水平越权(横向越权)

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、定义 攻击者可以访问和操作与其拥有同级权限的用户资源。 示例: 学生A在教务系统上正常只能修改自己的作业内容,但由于不合理的权限校验规则等原因,学生A可以修改学生B的内…

五种免费的Python开发环境及具体下载网址

五种免费的Python开发环境及具体下载网址 目录 五种免费的Python开发环境及具体下载网址1.Anaconda2.PyCharm Community Edition3.Visual Studio Code4.Jupyter Notebook5. WinPython Python编程可选择不同的开发工具环境进行,本文介绍五种常用的,读者可…

R语言使用dietaryindex包计算NHANES数据多种营养指数(2)

健康饮食指数 (HEI) 是评估一组食物是否符合美国人膳食指南 (DGA) 的指标。Dietindex包提供用户友好的简化方法,将饮食摄入数据标准化为基于指数的饮食模式,从而能够评估流行病学和临床研究中对这些模式的遵守情况,从而促进精准营养。 该软件…

WhatsApp封号怎么办?看看原因与解封方法

相信各位小伙伴已经发现,WhatsApp新一轮风控已经启动,不少小伙伴已经受到封号潮的冲击。无论是老号还是新号都难以幸免。为了防止WhatsApp客户数据和聊天信息的丢失,针对封号的防封攻略请收藏! 一、WhatsApp被封的8个原因 1、被过…

编译与链接(想了解编译与链接,那么看这一篇就足够了!)

前言:在我们练习编程的时候,我们只需要将代码写入、运行,就可以得到计算之后的结果了,但是你有没有想过,为什么就可以得到计算之后的结果呢,它的底层又到底是什么呢? ✨✨✨这里是秋刀鱼不做梦的…

算法之美:B+树原理、应用及Mysql索引底层原理剖析

B树的一种变种形式,B树上的叶子结点存储关键字以及相应记录的地址,同等存储空间下比B-Tree存储更多Key。非叶子节点不对关键字记录的指针进行保存,只进行数据索引 , 树的层级会更少 , 所有叶子节点都在同一层, 叶子节点的关键字从小到大有序排…

安装uim-ui插件不成功,成功解决

安装:这种安装,umi4 不支持,只有umi3才支持。而我发现官网现在默认使用的umi4。 yarn add umijs/preset-ui -D 解决:更改umi版本重新安装umi3 npm i ant-design/pro-cli3.1.0 -g #使用umi3 (指定umi3版本) pro create user-ce…

伪原创文章生成软件:自媒体文章写作好神器

自媒体的红利时代,许多人都纷纷参于其中,而文章写作是做自媒体的基本技能,但是随着技术的发展,如今,既使不会写作能力一样可以做起自媒体,方法就是利用伪原创文章生成软件来做内容的输出,其实伪…