五种情况,不加GAP锁,只加行锁

2024-08-26 12:52

本文主要是介绍五种情况,不加GAP锁,只加行锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

大家好,我是大都督周瑜,最近在整理MySQL源码的笔记,这里分享一篇出来,想看其他的可以关注我的公众号:IT周瑜。

在源码中有这么一段:
image.png
goto no_gap_lock表示加的锁类型为:LOCK_REC_NOT_GAP,也就是我们通常所理解的行锁,只锁记录行本身,不说记录前面的间隙。

上面代码中,如果进入else分支,那么锁的类型是LOCK_ORDINARY,它表示既锁记录本身,也锁记录前面的间隙,也就是我们常说的next-key锁,因此大家能猜到,那有没有一种锁类型只锁记录前面的间隙而不锁记录本身呢,当然有啦,那就是LOCK_GAP,对应源码为:
image.png

扯远了,我们还是回答本文的主题:什么时候不加GAP锁,只加行锁?

第一种情况

再看看前面的源码:
image.png
因此,只要符合if条件,进入no_gap_lock流程就是我们要的答案,由于if中都是或条件,因此我们只需要一个个条件进行分析就能得到答案。

首先,set_also_gap_locks为false,在源码中set_also_gap_locks默认为true,只在一个地方进行了赋值,赋值代码为:
image.png
第三个条件不用管,其他条件为:

  1. trx->isolation_level <= TRX_ISO_READ_COMMITTED:表示隔离级别是读未提交或读已提交
  2. prebuilt->select_lock_type != LOCK_NONE:表示当前SQL需要加锁
  3. thd_is_select(trx->mysql_thd)):当前SQL是select查询

其实很好理解,首先当前SQL得是查询并且想要加锁,也就是SELECT ... FOR UPDATESELECT... LOCK IN SHARE MODE两种情况,但是如果隔离级别是读未提交或读已提交,那么就不需要加GAP锁。

反过来理解就是如果当前SQL是查询并且想要加锁,但是如果隔离级别是可重复读或串行读,才需要加GAP锁。

因此,我们要理解GAP锁的作用是什么,GAP锁的作用就是:在一个事务中多次查询得到的结果得是一样的,特别是两次查询之间其他事务插入了新记录,第二次查询的时候也不能把新记录查出来,对应的隔离级别就是可重复读和串行读,所以当隔离级别是读未提交和读已提交时不需要加GAP锁。

第二种情况

image.png
srv_locks_unsafe_for_binlog是用在主从复制过程中的,这块暂时还没研究,AI给的答案是:

srv_locks_unsafe_for_binlog 参数设置为 ON 时,InnoDB 存储引擎会使用一种不太安全的锁定策略,这种策略可能会导致某些事务在从库上执行时产生不同的结果。这种锁定策略可能会提高性能,因为它减少了锁定等待时间,但可能会导致复制问题。
相反,当 srv_locks_unsafe_for_binlog 参数设置为 OFF(默认值)时,InnoDB 存储引擎会使用更安全的锁定策略,以确保事务的可重复性,从而保证在复制环境中数据的一致性。这种策略可能会降低性能,因为它可能会增加锁定等待时间,但可以确保主从数据的一致性。
在大多数情况下,特别是在生产环境中,应该将 srv_locks_unsafe_for_binlog 设置为 OFF,以确保数据的一致性和事务的完整性。只有在非常特殊的情况下,并且对可能产生的复制问题有充分的了解和接受时,才应该考虑将其设置为 ON

第三种情况

第三个条件是trx->isolation_level <= TRX_ISO_READ_COMMITTED,和前面set_also_gap_locks的判断类似,对于隔离级别是读未提交或读已提交则不需要加GAP锁。

第四种情况

第四个条件为(unique_search && !rec_get_deleted_flag(rec, comp))

  • unique_search表示当前查询是唯一搜索,表示只会搜索出一条记录
  • !rec_get_deleted_flag(rec, comp)表示搜索出来的记录delete mark为false,表示记录没有被删除,实际上InnoDB中的删除记录只是将delete mark设置为true

也就是说,当前SQL已经查到了一条记录,并且可以判断出当前SQL只有可能查出一条数据,那么就不需要对查出来的记录加GAP锁了,因为只有可能查出一条记录,因此这里的重点是:什么是unique_search?

如何理解unique_search?

上代码:
image.png

  1. match_mode == ROW_SEL_EXACT:当前查询是等值查询
  2. dict_index_is_unique(index):当前索引是唯一索引
  3. dtuple_get_n_fields(search_tuple) == dict_index_get_n_unique(index):查询条件能覆盖索引的全部字段,比如a,b,c组成的联合唯一索引,那么查询条件中必须包含a,b,c三个字段
  4. (dict_index_is_clust(index) || !dtuple_contains_null(search_tuple)):以上三条件还不足以保证只会查出一条数据,因为唯一索引有可能允许字段为null,因此要么索引是聚集索引(字段不能为NULL),或者查询条件中不包含等于null的查询(只针对索引的字段)

以上四个条件全部成立就表示本次查询是unique_search。

当然还需要注意,就算是unique_search,如果当前SQL没有查询到记录,比如表里只有id=1、id=2、id=3三条记录,此时查询id=4,那么此时是会加GAP锁的,准确一点加的是LOCK_ORDINARY锁,也就是next-key锁。
image.png

那是给哪条记录加的锁呢:
image.png
页里面的最大记录,锁最大记录之前的间隙,这样就不会允许其他事务插入id=4的记录了。

第五种情况

dict_index_is_spatial(index),表示当前索引是空间索引,不需要管。

谢谢大家的点赞和关注,欢迎在评论区留言讨论,也可以关注我的公众号:IT周瑜,谢谢。

这篇关于五种情况,不加GAP锁,只加行锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

如何保证android程序进程不到万不得已的情况下,不会被结束

最近,做一个调用系统自带相机的那么一个功能,遇到的坑,在此记录一下。 设备:红米note4 问题起因 因为自定义的相机,很难满足客户的所有需要,比如:自拍杆的支持,优化方面等等。这些方面自定义的相机都不比系统自带的好,因为有些系统都是商家定制的,难免会出现一个奇葩的问题。比如:你在这款手机上运行,无任何问题,然而你换一款手机后,问题就出现了。 比如:小米的红米系列,你启用系统自带拍照功能后

Windows11电脑上自带的画图软件修改照片大小(不裁剪尺寸的情况下)

针对一张图片,有时候上传的图片有大小限制,那么在这种情况下如何修改其大小呢,在不裁剪尺寸的情况下 步骤如下: 1.选定一张图片,右击->打开方式->画图,如下: 第二步:打开图片后,我们可以看到图片的大小为82.1kb,点击上面工具栏的“重设大小和倾斜”进行调整,如下: 第三步:修改水平和垂直的数字,此处我修改为分别都修改为50,然后保存,可以看到大小变成63.5kb,如下:

postgres数据库中如何看查询是否走索引,以及在什么情况下走索引

在 PostgreSQL 中,可以通过 EXPLAIN 或 EXPLAIN ANALYZE 查看查询计划,以判断查询是否使用了索引。除此之外,了解索引的使用条件对于优化查询性能也很重要。 1. 如何查看查询是否使用索引 使用 EXPLAIN 查看查询计划 EXPLAIN 显示 PostgreSQL 如何执行查询,包括是否使用索引。 EXPLAIN SELECT * FROM users WH

linux 查看内存使用情况

Linux查看CPU和内存使用情况:http://www.cnblogs.com/xd502djj/archive/2011/03/01/1968041.html 在做Linux系统优化的时候,物理内存是其中最重要的一方面。自然的,Linux也提供了非常多的方法来监控宝贵的内存资源的使用情况。下面的清单详细的列出了Linux系统下通过视图工具或命令行来查看内存使用情况的各种方法。 1. /pr

ubuntu内存资源使用情况监视

此处分享一个可以查看ubuntu系统中资源使用情况的指令,只需要在终端中输入一下这条指令即可: gnome-system-monitor

在不损坏数据的情况下给WIN7重新划分分区

小易接到个求助电话:我的机器上已经装好了系统,但是只有一个分区。我不想重装系统重新分区,能不能再分出一个分区?   这个故障可能是困惑很多网友的一个故障。一般,有一些第三方的软件可以实现这些功能。但是,现在在 Windows Vista/Windows 7 里允许你对现有分区大小进行一定范围的调整。   来看一下操作办法:   准备工作   这个操作必须要求你的文件系统是 N

关于Qt在子线程中使用通讯时发生无法接收数据的情况

在多线程应用中,串口通讯或TCP通讯的场景常常涉及到持续的读写操作,如果子线程处理不当,可能会导致信号阻塞问题。本文将通过串口通讯或TCP通讯为例,详细解释如何在多线程环境中避免信号阻塞,并提供代码示例。 1. 问题背景 假设我们在一个应用程序中使用多线程处理串口或TCP通讯,通常会在子线程中实现持续的数据读取。为了确保实时处理数据,常见的做法是在子线程的 run() 方法中使用 while

【linux 服务器运行情况】了解Linux服务器运行情况

1、free 在Linux下,使用free命令获取当前内存的使用情况 [root@izbp1f0leha0lvmqfhigzpz code]# free -htotal used free shared buff/cache availableMem: 1.8G 84M 173M 38

正点原子阿尔法ARM开发板-IMX6ULL(二)——介绍情况以及汇编

文章目录 一、裸机开发(21个)二、嵌入式Linux驱动例程三、汇编3.1 处理器内部数据传输指令3.2 存储器访问指令3.3 压栈和出栈指令3.4 跳转指令3.5 算术运算指令3.6 逻辑运算指令 一、裸机开发(21个) 二、嵌入式Linux驱动例程 三、汇编 我们在进行嵌入式 Linux 开发的时候是绝对要掌握基本的 ARM 汇编,因为 Cortex-A 芯片一