五种情况,不加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

相关文章

Mysql中深分页的五种常用方法整理

《Mysql中深分页的五种常用方法整理》在数据量非常大的情况下,深分页查询则变得很常见,这篇文章为大家整理了5个常用的方法,文中的示例代码讲解详细,大家可以根据自己的需求进行选择... 目录方案一:延迟关联 (Deferred Join)方案二:有序唯一键分页 (Cursor-based Paginatio

Redis中的常用的五种数据类型详解

《Redis中的常用的五种数据类型详解》:本文主要介绍Redis中的常用的五种数据类型详解,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Redis常用的五种数据类型一、字符串(String)简介常用命令应用场景二、哈希(Hash)简介常用命令应用场景三、列表(L

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

查看Oracle数据库中UNDO表空间的使用情况(最新推荐)

《查看Oracle数据库中UNDO表空间的使用情况(最新推荐)》Oracle数据库中查看UNDO表空间使用情况的4种方法:DBA_TABLESPACES和DBA_DATA_FILES提供基本信息,V$... 目录1. 通过 DBjavascriptA_TABLESPACES 和 DBA_DATA_FILES

C/C++随机数生成的五种方法

《C/C++随机数生成的五种方法》C++作为一种古老的编程语言,其随机数生成的方法已经经历了多次的变革,早期的C++版本使用的是rand()函数和RAND_MAX常量,这种方法虽然简单,但并不总是提供... 目录C/C++ 随机数生成方法1. 使用 rand() 和 srand()2. 使用 <random

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

MySQL进阶之路索引失效的11种情况详析

《MySQL进阶之路索引失效的11种情况详析》:本文主要介绍MySQL查询优化中的11种常见情况,包括索引的使用和优化策略,通过这些策略,开发者可以显著提升查询性能,需要的朋友可以参考下... 目录前言图示1. 使用不等式操作符(!=, <, >)2. 使用 OR 连接多个条件3. 对索引字段进行计算操作4

MySQL表锁、页面锁和行锁的作用及其优缺点对比分析

《MySQL表锁、页面锁和行锁的作用及其优缺点对比分析》MySQL中的表锁、页面锁和行锁各有特点,适用于不同的场景,表锁锁定整个表,适用于批量操作和MyISAM存储引擎,页面锁锁定数据页,适用于旧版本... 目录1. 表锁(Table Lock)2. 页面锁(Page Lock)3. 行锁(Row Lock

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键