技术合集 | 【MySQL技术专题】「数据库锁技术」深入浅出透析MySQL数据库的锁基础概念和原理(上下全)

news2024/11/17 17:49:35

上篇

前提介绍

在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足。

本文内容

  • 本文主要介绍:行级锁、表级锁、页级锁的相关概念以及原理介绍

  • 本文主要介绍:共享锁、排它锁的相关概念以及原理介绍

  • 本文主要介绍:意向锁共享锁、意向排它锁的相关概念以及作用介绍

行级锁和表级锁及页级锁

在MySQL数据库体系中,可以按照锁的粒度把数据库锁分为行级锁(Innodb引擎)、表级锁(MyISam引擎)和页级锁(BDB引擎 )

行级锁

  • 行级锁是MySQL中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。

    • 行级锁能大大减少数据库操作的冲突

    • 其加锁粒度最小,但加锁的开销也最大

行级锁分为共享锁和排他锁。具体针对于这两种锁会在后续介绍

  • 特点

    • 开销大,加锁慢

    • 会出现死锁

    • 锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

表级锁

表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持

  • 最常使用的MYISAM与INNODB都支持表级锁定。

表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)

  • 特点

    • 开销小,加锁快

    • 不会出现死锁

    • 锁定粒度大,发出锁冲突的概率最高,并发度最低

页级锁

页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。

表级锁速度快,但冲突多,行级冲突少,但速度慢。

所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁

  • 特点

    • 开销和加锁时间界于表锁和行锁之间;

    • 会出现死锁;

    • 锁定粒度界于表锁和行锁之间,并发度一般


MySQL常用存储引擎的锁机制

  • MyISAM和MEMORY采用表级锁(table-level locking)

  • BDB采用页面锁(page-level locking)或表级锁,默认为页面锁

  • InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

Innodb中的行锁与表锁

  • Innodb引擎中既支持行锁也支持表锁,那么什么时候会锁住整张表,什么时候或只锁住一行呢?

    • InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。

    • InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。

  • 在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。

    • 由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。

    • 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁

即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的,如果 MySQL认为全表扫效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁

因此,在分析锁冲突时, 别忘了检查 SQL 的执行计划,以确认是否真正使用了索引。

行级锁与死锁

MyISAM中是不会产生死锁的,因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么全部等待

  • 在InnoDB中,锁是逐步获得的,就造成了死锁的可能。行级锁并不是直接锁记录,而是锁索引

    • 索引分为主键索引和非主键索引两种:

      • 如果一条语句操作了主键索引,MySQL就会锁定这条主键索引

      • 如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引

在UPDATE、DELETE操作时,MySQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的next-key locking

  • 当两个事务同时执行:

    • 一个锁住了主键索引,在等待其他相关索引

    • 另一个锁定了非主键索引,在等待主键索引。这样就会发生死锁

发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。

  • 有多种方法可以避免死锁,这里只介绍常见的三种

    1. 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

    2. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

    3. 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

共享锁与排他锁

上面介绍过,行级锁是MySQL中锁定粒度最细的一种锁,行级锁能大大减少数据库操作的冲突。

行级锁分为共享锁和排他锁两种,本文将详细介绍共享锁及排他锁的概念、使用方式及注意事项等。

共享锁(Share Lock)

共享锁又称读锁,是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁

如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据

用法

SELECT ... LOCK IN SHARE MODE;
  • 在查询语句后面增加LOCK IN SHARE MODEMySQL会对查询结果中的每行都加共享锁

  • 当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据

排他锁(exclusive Lock)

  • 排他锁又称写锁,如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据

对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁(X)

用法

SELECT ... FOR UPDATE;

在查询语句后面增加FOR UPDATE,MySQL会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。

意向锁

意向锁是一种不与行级锁冲突表级锁,这一点非常重要。意向锁分为两种: 1. 意向共享锁(intention shared lock, IS):事务有意向对表中的某些行加共享锁(S锁) 2. 意向排他锁(intention exclusive lock, IX):事务有意向对表中的某些行加排他锁(X锁) 即:意向锁是有数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享 / 排他锁之前,InnoDB会先获取该数据行所在在数据表的对应意向锁

InnoDB支持多粒度锁,特定场景下,行级锁可以与表级锁共存。

  • 意向锁之间互不排斥,但除了IS与S兼容外,意向锁会与共享锁 / 排他锁 互斥。

  • IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突。

  • 意向锁在保证并发性的前提下,实现了行锁和表锁共存且满足事务隔离性的要求。


  • 意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁

  • 意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁

对于一般的Select语句,InnoDB不会加任何锁(快照读)。


下篇

MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大大减少数据库操作的冲突。行级锁分为共享锁和排他锁两种,本文将详细介绍共享锁及排他锁的概念、使用方式及注意事项等。

加锁目的

数据库是一个多用户使用的共享资源当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性


锁是用于管理对公共资源的并发控制。也就是说在并发的情况下,会出现资源竞争,所以需要加锁。加锁解决了 多用户环境下保证数据库完整性和一致性


Lock的对象是事务用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。


死锁

死锁是并发系统中常见的问题,同样也会出现在数据库MySQL的并发读写请求场景中。当两个及以上的事务,双方都在等待对方释放已经持有的锁或因为加锁顺序不一致造成循环等待锁资源,就会出现“死锁”。常见的报错信息为 ” Deadlock found when trying to get lock… ”。


死锁场景

举例来说A事务持有X1锁 ,申请 X2 锁,B事务持有 X2 锁,申请 X1 锁。A 和 B 事务持有锁并且申请对方持有的锁进入循环等待,就造成了死锁。

InnoDB 锁类型

为了分析死锁,我们有必要对 InnoDB 的锁类型有一个了解。


MySQL InnoDB引擎实现了标准行级别锁:共享锁( S lock ) 和排他锁 ( X lock )

  • 不同事务可以同时对同一行记录加S锁
  • 如果一个事务对某一行记录加 X 锁,其他事务就不能加 S 锁或者 X 锁,从而导致锁等待

如果事务T1持有行r的S锁,那么另一个事务 T2 请求r的锁时,会做如下处理:

  • T2 请求 S 锁立即被允许,结果 T1 T2 都持有 r 行的 S 锁
  • T2 请求 X 锁不能被立即允许

如果T1持有r的 X 锁,那么T2请求r的X、S锁都不能被立即允许,T2 必须等待 T1 释放 X 锁才可以,因为 X 锁与任何的锁都不兼容。共享锁和排他锁的兼容性如下所示:


间隙锁(gap lock)

间隙锁锁住一个间隙以防止插入。假设索引列有2, 4, 8 三个值,如果对 4 加锁,那么也会同时对(2,4)和(4,8)这两个间隙加锁其他事务无法插入索引值在这两个间隙之间的记录

但是,间隙锁有个例外:

如果索引列是唯一索引,只会锁住这条记录(只加行锁),而不会锁住间隙
对于联合索引且是唯一索引,如果 where 条件只包括联合索引的一部分,那么依然会加间隙锁。

产生间隙的条件

  1. 使用普通索引锁定
  2. 使用多列唯一索引
  3. 使用唯一索引锁定多行记录

next-key lock(Record Lock + Gap Lock 临键锁)

next-key lock 实际上就是 行锁+这条记录前面的 gap lock 的组合。假设有索引值10,11,13和 20,那么可能的 next-key lock 包括:

- (负无穷,10]
- (10,11]
- (11,13]
- (13,20]
- (20,正无穷)

在RR隔离级别下,InnoDB 使用 next-key lock 主要是防止幻读问题产生。

临键锁,是记录锁与间隙锁的组合,它的封锁范围,既锁住记录本身还锁住索引之间的间隙。

 注:临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。

意向锁( Intention lock )


InnoDB为了支持多粒度的加锁,允许行锁和表锁同时存在为了支持在不同粒度上的加锁操作,InnoDB 支持了额外的一种锁方式,称之为意向锁( Intention Lock )意向锁是 InnoDB 自动加的,不需用户干预。


意向锁是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁。

意向锁分为两种:

  • 意向共享锁( IS ):事务有意向对表中的某些行加共享锁:(事务务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁
  • 意向排他锁( IX ):事务有意向对表中的某些行加排他锁:(事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁

由于InnoDB存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫描以外的任何请求表级意向锁与行级锁的兼容性如下所示:

意向锁有什么用?
主要作用是处理行锁和表锁之间的矛盾,能够显示“某个事务正在某一行上持有了锁,或者准备去持有锁”
当我们需要加一个排他锁时,需要根据意向锁去判断表中有没有数据行被锁定


比如事务A要在一个表上加S锁,如果表中的一行已被事务B加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐行检查锁标志的开销将很大,系统的性能将会受到影响。为了解决这个问题,可以在表级上引入新的锁类型来表示其所属行的加锁情况,这就引出了“意向锁”的概念


举个例子,如果表中记录1亿,事务A把其中有几条记录上了行锁了,这时事务B需要给这个表加表级锁,如果没有意向锁的话,那就要去表中查找这一亿条记录是否上锁了。

如果存在意向锁,那么假如事务A在更新一条记录之前,先加意向锁,再加X锁,事务B先检查该表上是否存在意向锁,存在的意向锁是否与自己准备加的锁冲突,如果有冲突,则等待直到事务A释放,而无须逐条记录去检测
事务B更新表时,其实无须知道到底哪一行被锁了,它只要知道反正有一行被锁了就行了。


行锁的算法

Record Lock(单行记录)


单条索引上加锁,record lock 永远锁的是索引,而非数据本身,如果innodb表中没有索引,那么会自动创建一个隐藏的聚集索引,锁住的就是这个聚集索引


当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁,这个类似于表锁,但原理上和表锁应该是完全不同的

记录锁的条件

命中单行记录并且命中的条件字段是唯一索引或者主索引;
update user_info set name=’张三’ where id=1;
//这里的id是唯一索引,使用了Record Lock

Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定


插入意向锁( Insert Intention lock )

插入意向锁是在插入一行记录操作之前设置的一种间隙锁这个锁释放了一种插入方式的信号,即多个事务在相同的索引间隙插入时如果不是插入间隙中相同的位置就不需要互相等待。假设某列有索引值2,6,只要两个事务插入位置不同(如事务 A 插入3,事务 B 插入4),那么就可以同时插入

锁模式兼容矩阵

横向是已持有锁,纵向是正在请求的锁:

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

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

相关文章

论文速读系列二:YOLO3D、PIXOR、HDNET、Voxel-FPN、Fast Point RCNN

如有错误,恳请指出。 参考网上资料,对一些经典论文进行快速思路整理 文章目录1. YOLO3D2. PIXOR3. HDNET(PIXOR)4. Voxel-FPN5. Fast Point RCNN1. YOLO3D paper:《YOLO3D: End-to-end real-time 3D OrientedObject B…

领英怎么用多个账号一起开发客户?进阶知识

1.如何注册账号? LinkedIn经历调整 2021年12月14日起,领英(LinkedIn)正式被改版为领英职-场。在改版后的领英职-场上,我们既无法进行主动搜-索客户,添-加好友,也无法查看和发布动态内容,完完全全的变成了一…

ChatGPT 常见错误原因及解决方案:报错、回答不完整等

最近,由人工智能实验室 OpenAI 发布的对话式大型语言模型 ChatGPT 火得一塌糊涂。它可以与人类轻松地对话,无论是多么奇葩的问题 ChatGPT 都不在话下。在体验 ChatGPT 的同时我们也会遇到各种各样的问题,这里我总结了其对话过程中可能会发生的…

springboot中如何实现跨域请求

Springboot中如何处理跨域请求 一.什么是跨域? 我们知道Url的一般格式:协议 域名(子域名 主域名) 端口号 资源地址 比如: https://www.itquanmingxing.cn:8080/users 是由https www itquanmingxing.cn 8080 users组成…

普通程序员可以怎么做搞钱程序?

最近海洋问题实在是很严重,人类活动带来的垃圾污染等问题使海洋生物得到了很大的压力。 每年鱼类等海洋生物体内的塑料海量越来越多,不仅仅是由于日常人类日常使用的垃圾袋引起的。 还有很多方面的原因,最直接的因素就是去看海的游客遗留下…

云计算自学笔记(不定期更新)

管道命令使用 linux管道相关命令__小笼包_的博客-CSDN博客_linux管道命令 [cut ]:命令的功能是用于按列提取文件内容 按照字符提取命令:head -2 2.txt | cut -c 5 查看前两行,并按照字符提取第五个字符 -c 按照字符提取 截取出…

剑指Offer40——最小的k个数

摘要 剑指 Offer 40. 最小的k个数 一、排序方法 1.1 排序的方法分析 对原数组从小到大排序后取出前 k 个数即可。 1.2 复杂度分析 时间复杂度:O(nlog⁡n)O,其中 n 是数组 arr 的长度。算法的时间复杂度即排序的时间复杂度。 空间复杂度:…

MQ高级(四)MQ集群

一、集群分类 RabbitMQ的是基于Erlang语言编写,而Erlang又是一个面向并发的语言,天然支持集群模式。 RabbitMQ的集群有两种模式: (1)普通集群:是一种分布式集群,将队列分散到集群的各个节点&…

【Flink】复杂事件处理CEP底层实现(有限状态机)和应用

文章目录一 Flink CEP简介1 什么是复杂事件处理CEP2 Flink CEP(1)导入依赖(2)代码编写(3)优化模板3 实现CEP底层 -- 有限状态机4 使用CEP处理超时事件一 Flink CEP简介 1 什么是复杂事件处理CEP 一个或多…

239页11万字新型智慧城市运营中心IOC大数据平台建设方案

目录 1 概述 1.1 建设目标 1.2 建设内容 1.3 建设步骤 2 项目建设方案 2.1 总体设计方案 2.2 支撑平台方案 2.2.1 数据治理平台 2.2.2 可视化平台 2.2.3 城市感知平台 2.3 应用系统方案 2.3.1 综合监测系统 2.3.2 事件管理系统 2.3.3 联动指挥系统 2.3.4 辅助决策…

自定义镜像上传阿里云

目录标题一、Docker制作jdk镜像1.jdkv.1.0的制作1.1创建文件夹上传jdk的安装包,和在同级目录下编写Dockerfile文件1.2.编写 Dockerfile 文件1.3.执行Dockerfile文件,初次依赖镜像的时候会下载相应镜像2.jdk2.0的制作3.jdk3.0的制作二、Docker镜像上传至阿里云前期准…

19.5 迭代器的概念和分类

一:迭代器基本概念:第十三章第九节 迭代器:是一个“可遍历STL容器全部或者部分元素”的对象(行为类似于指针的对象); 迭代器用来表现容器中的某一位置;迭代器紧密依赖于容器,迭代器…

2023年天津仁爱学院专升本动画、化学工程与工艺专业介绍

2023年天津仁爱学院专升本专业课动画专业、化学工程与工艺专业介绍 (一)动画专业 动画专业以行业发展对应用型人才需求为导向,不断提高学生就业质量为目标,针对学生特点,积极拓展动画应用领域,设有影视后期…

JSP SSH超市管理统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 JSP 超市管理统是一套完善的web设计系统(系统采用ssh框架进行设计开发),对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发 JSP SSH超市管理统myeclipse开发…

【Leetcode每日一题】子序列宽度之和,匹配子序列的单词数,最大平均值和的分组

891. 子序列宽度之和 计算的是【贡献】。 首先观察发现,顺序不影响结果。然后比如1,作为最大元素贡献为0,而作为最小元素贡献为每个子序列的【最大-1】,一共有多少个作为最小元素的子序列,对答案的贡献就是-1*(个数)。…

【✨十五天搞定电工基础】正弦交流电路的分析(下)

目录 五、复杂正弦交流电路的分析(下) 六、功率因数的提高 七、谐振电路 1、串联谐振 2、并联谐振 八、课后习题 1、正弦量三要素,相位 2、RLC串联问题 3、复杂正弦交流电路问题 4、谐振问题 五、复杂正弦交流电路的分析&#x…

Metabase学习教程:权限-4

高级数据沙盒:限制对列的访问 了解如何使用已保存的SQL查询对表进行沙盒处理,并根据用户属性限制用户可以查看的列。 我们的文章行权限涵盖了沙盒(商业版本). 我们将沙盒定义为一种根据用户身份指定用户可以访问哪些数据的方法,…

【TOTP】基于时间的动态密码及其工程实践

探究了常见的动态密码的实现方式及其底层原理,并基于java做出了工程实践。 文章目录A.来源于一个现象的好奇B.2FAC.TOTP1.什么是TOTP2.原理详解(基于java-totp项目分析)3.这样真的安全吗4.常见的支持TOTP的软件1.Google Authenticator2.Micro…

RCNN学习笔记-MobileNet3

更新Block(bneck倒残差结构) 1.加入SE(自注意力模块squeeze-and-excite bottleneck)模块。当stride1(高和宽是不会变化的)且inputc outputc才有shortcut连接。 相反,我们将它们全部替换为扩展层中通道数量的1/4。我…

功率放大器输出阻抗的影响因素有哪些原因

关于功率放大器的疑问有很多,前阵子有人咨询影响功率放大器输出阻抗的有哪些因素,今天就请安泰电子来为大家解释,同时再为大家科普一下功率放大器的知识。 图:信号源和负载的放大器的简化模型 在搞清楚影响功率放大器输出阻抗因素…