MySQL InnoDB锁算法,可算搞明白了

2023-12-03 15:08

本文主要是介绍MySQL InnoDB锁算法,可算搞明白了,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在Innodb事务隔离性实现原理,你了解吗?里讲了行锁,但Innodb除了行锁还有间隙锁(Gap Lock)和next-key lock。这些锁之间有什么关系呢?我们经常会听到全局锁、表级锁、行锁,这些又是什么?这篇文章带你搞懂这些内容。本篇如果不做特别说明,隔离级别都为可重复读。

锁级别

MySQL锁级别有三类:全局锁、表级锁、行锁。

全局锁

对整个数据库实例加锁

  • 加锁命令:Flush tables with read lock (FTWRL)

  • 解锁命令:

  • unlock tables

  • 断开加锁session的连接

  • 目的:使整个库处于只读状态

  • 规则:全局锁加锁成功,会阻塞所有级别的写锁,读锁不受影响

  • 使用场景:如做全库逻辑备份

  • 影响:主库加锁,导致任何更新操作都会被阻塞,业务停摆;从库加锁,导致主从延迟

表级别锁

对表进行加锁,有三种:

  • 两种来自MySQL,为表锁和元数据锁(meta data lock,MDL)

  • 一种来自Innodb,为意向锁,分意向共享锁(IS)和意向排它锁(IX)

表锁
  • 加锁命令:lock tables … read/write

  • 解锁命令:

  • unlock tables

  • 断开加锁session的连接

  • 目的:使指定表处于只读、只写状态

  • 规则:

    | 读锁 | 写锁 |
    | — | — | — |
    | 读锁 | 不冲突 | 冲突 |
    | 写锁 | 冲突 | 冲突 |

  • 使用场景:如无行锁的存储引擎可用来处理并发问题

  • 影响:lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象,即如果设置表为只读,本线程也无写的能力

MDL
  • 加解锁:MDL不需要显式使用,在访问一个表的时候会被自动加上

  • 目的:保证读写的正确性,方便处理DDL操作和DML操作的冲突

  • 规则:当对一个表做增删改查操作的时候,自动加 MDL读锁;当要对表做结构变更操作的时候,自动加 MDL 写锁。MDL读锁和大家平时理解的读锁不一样,增删改查加的都是读锁。

    | MDL读锁 | MDL写锁 |
    | — | — | — |
    | MDL读锁 | 不冲突 | 冲突 |
    | MDL写锁 | 冲突 | 冲突 |

意向锁
  • 加解锁:意向锁不需要显式使用,在访问一个表的时候会被自动加上

  • 事务想要给数据库某些行加共享锁,需要先加上意向共享锁

  • 事务想要给数据库某些行加互斥锁,需要先加上意向互斥锁

  • 目的:为了实现多粒度锁,和表锁做冲突。当加行锁的时候,同时加了意向锁,这样要加表锁的时候,根据意向锁的情况,能迅速断定能否加表锁。

  • 规则:意向锁不会与行级的共享 / 排他锁互斥

    | 意向共享锁 | 意向排它锁 |
    | — | — | — |
    | 意向共享锁 | 不冲突 | 冲突 |
    | 意向排它锁 | 冲突 | 冲突 |

行级别锁

对数据表中行记录加锁。MySQL 的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如MyISAM 引擎就不支持行锁。

  • 加锁:select lock in share mode(共享锁S), select for update ; update, insert ,delete(排它锁X)

  • 解锁:事务commit后释放

  • 目的:做并发控制

  • 规则:

| 共享锁 | 排它锁 |
| — | — | — |
| 共享锁 | 不冲突 | 冲突 |
| 排它锁 | 冲突 | 冲突 |

冲突

本想把所有的锁冲突情况汇集在一起,不过有些锁之间是共生关系,没想好怎么整理。大家如果有好的建议可以留言说一下。

| FTWRL | 表读锁 | 表写锁 | MDL读锁 | MDL写锁 | 意向共享锁 | 意向排它锁 | 行共享锁 | 行排它锁 |
| — | — | — | — | — | — | — | — | — | — |
| FTWRL | | | | | | | | | |
| 表读锁| | | | | | | | | |
| 表写锁 | | | | | | | | | |
| MDL读锁 | | | | | | | | | |
| MDL写锁 | | | | | | | | | |
| 意向共享锁 | | | | | | | | | |
| 意向排它锁| | | | | | | | | |
| 行共享锁| | | | | | | | | |
| 行排它锁| | | | | | | | | |

锁算法

怎么计算哪些行是需要加锁的呢?这就涉及到锁的算法。

三种

首先我们要知道,锁是加在索引上的,一张表可能有多个索引,根据情况不同,一个语句产生的锁可能加在一个或多个索引上。

锁算法有三种,分别为:

行锁:单个行记录上的锁

Gap Lock:间隙锁,锁定一个范围,但不包含记录本身;间隙锁之间没有冲突;间隙锁在可重复读隔离级别下才有效

Next key Lock:Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身

加锁规则

下面是林晓斌总结出的规则,适用于 5.x 系列 <=5.7.24,8.0 系列 <=8.0.13。

为两个“原则”、两个“优化”和一个“bug”。

  1. 原则 1:加锁的基本单位是 next-key lock。next-key lock 是前开后闭区间。

  2. 原则 2:查找过程中访问到的对象才会加锁。

  3. 优化 1:索引上的等值查询,给主键/唯一索引加锁,数据中查找到指定行,next-key lock退化为行锁。

  4. 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next key lock 退化为间隙锁。

  5. 一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

即使不看代码,这些规则也很符合解决问题的思路。

  1. 以next-key lock为基本单位,因为它是范围最广的锁,如果锁的范围大了,后面删减

  2. 如果是主键/唯一索引上等值查询,如果找到对应行,说明最多只会有这一行,退化成行锁毫无问题,还能减少锁的范围

  3. 如果索引上等值查询,最后一个值不满足等值条件,肯定不必锁

  4. 只有访问的对象才加锁,因为只需要保证当前语句重复执行时获取到的数据是不变的即可,如果语句没用到其它索引,所以自然不必管其它对象

  5. 两个没想通的地方

  • 一是唯一索引上的范围查询会访问到不满足条件的第一个值为止,根据唯一索引的特性,理论上不需要再继续查找了

  • 二是对索引上的范围查找,如c>10 && c<15,如果最后一个值不满足条件,理论上也可退化为间隙锁

实例

让我们根据实例,验证一下加锁规则。

先创建表结构与数据:

CREATE TABLE `t` (`id` int(11) NOT NULL,`c` int(11) DEFAULT NULL,`d` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `c` (`c`)
) ENGINE=InnoDB;insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);

根据主键/唯一索引、普通索引、无索引,进行等值查询、范围查询,查看锁定情况:

等值查询范围查询
主键/唯一索引请添加图片描述最终在主键,锁住范围为(5,10)。因为是在主键索引上进行查找,所以无需从头查找,直接定位到(5,10],根据原则1加next key lock;而又因为是等值查询,最后一个值为10,不等于7,根据优化2,退化为间隙锁。请添加图片描述最终在主键锁住[10,15]。因为从>=10,锁(5,10],根据优化1只锁10,对于<11,锁住(10,15]。请添加图片描述最终在主键锁住(10,20]。因为>10,锁(10,15];根据bug,会访问到不满足条件的第一个值为止,所以继续锁(15,20]。
普通索引请添加图片描述最终在索引C,锁住范围(0,10)。因为在C索引上进行查找,根据原则1,锁(0,5],向右继续遍历,锁(5,10];根据优化2,退化为(5,10),最终锁定范围为(0,10);因为session A只select id,C为覆盖索引,所以根本不需要遍历主键索引,根据原则2,主键索引没有加锁,所以实现了session B和session C的效果。请添加图片描述最终索引C和主键索引锁住(5,15]。因为C>=10,锁住(5,10],向右继续查找,锁住(10,15],同时会对主键进行加锁。
无索引可认为锁[负无穷,正无穷]可认为锁[负无穷,正无穷]

根据对实例的分析,大家加锁的时候,尽量加在主键/唯一索引上,并确保值确实存在。在这种情况下,添加的是行锁,冲突最小。

锁查看

不同版本查看方案加锁方案不一致,对于8.0版本,

  1. 可用 select * from performance_schema.data_locks 进行查看。

  2. 可查看锁日志:

    show variables like ‘innodb_status_output’;

    set GLOBAL innodb_status_output=ON;

    set GLOBAL innodb_status_output_locks=ON;

    show engine innodb status ;

幻读

间隙锁在可重复读隔离级别下才有效。next key lock能够解决幻读问题。如果没有这些锁算法,则重复读隔离级别下,读出的行数可能不同,违反了可重复读的含义。

在MySQL官方文档中,将不可重复读定义为Phantom Problem,即幻象问题。

在Next-Key Lock算法下,对于索引的扫描,不仅仅是锁住扫描到的索引,而且还锁住这些索引覆盖的范围(gap)。因此对于这个范围内的插入都是不允许的。这样就避免了另外的事务在这个范围内插入数据导致的不可重复读的问题。

有两个重点内容需要再说明一下:

  1. 在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。

  2. 幻读仅专指“新插入的行”。

资料

  1. mysql的innodb有哪几种锁_MySQL InnoDB 引擎中的 7 种锁类型,你都知道吗?

  2. MySQL 全局锁和表锁是什么

  3. MySQL学习笔记(三)—数据库意向锁和元数据锁

  4. mysql锁系列之全局锁

  5. MySQL技术内幕:InnoDB存储引擎

  6. mysql中查看sql语句的加锁信息

  7. mysql sys 查看锁_mysql8.0查看锁信息

  8. Mysql 锁表日志查看

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

图片

往期文章回顾:

  1. 设计模式

  2. 招聘

  3. 思考

  4. 存储

  5. 算法系列

  6. 读书笔记

  7. 小工具

  8. 架构

  9. 网络

  10. Go语言

这篇关于MySQL InnoDB锁算法,可算搞明白了的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/449877

相关文章

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig