【数据库】间隙锁Gap Lock

什么是间隙锁

间隙锁(Gap Lock):间隙锁是(RR级别下)一个在索引记录之间的间隙上的锁,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。间隙锁(Gap Lock)是Innodb在可重复读提交下为了解决幻读问题时引入的锁机制

当我们用范围条件而不是相等条件索引数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)"。InnoDB也会对这个"间隙"加锁,它锁住的是多行,是一个数据范围,这种锁机制就是所谓的间隙锁(Next-Key锁)。

间隙锁的危害

因为Query执行过程中通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,也造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。

间隙锁与死锁

最近用户反馈说系统老是出现insert时,等待超时了,最后发现是insert间隙锁!间隙锁是innodb中行锁的一种, 但是这种锁锁住的却不止一行数据,他锁住的是多行,是一个数据范围。间隙锁的主要作用是为了防止出现幻读,但是它会把锁定范围扩大,

有时候也会给我们带来麻烦,我们就遇到了。 在数据库参数中, 控制间隙锁的参数是:innodb_locks_unsafe_for_binlog

这个参数默认值是OFF, 也就是启用间隙锁, 他是一个bool值, 当值为true时表示disable间隙锁。

那为了防止间隙锁是不是直接将innodb_locaks_unsafe_for_binlog设置为true就可以了呢? 不一定!

而且这个参数会影响到主从复制及灾难恢复, 这个方法还尚待商量。

很容易产生间隙锁的位置

间隙锁的出现主要集中在同一个事务中先delete后 insert的情况下, 当我们通过一个参数去删除一条记录的时候,

如果参数在数据库中存在,那么这个时候产生的是普通行锁,锁住这个记录, 然后删除, 然后释放锁。

如果这条记录不存在,就有问题了, 数据库会扫描索引,发现这个记录不存在, 这个时候的delete语句获取到的就是一个间隙锁,然后数据库会向左扫描扫到第一个比给定参数小的值,向右扫描扫描到第一个比给定参数大的值, 然后以此为界,构建一个区间, 锁住整个区间内的数据, 一个特别容易出现死锁的间隙锁诞生了。间隙锁加锁是非互斥的,AB都删除同一个不同在的数据,产生了两个一样的互斥锁,然后都去插入数据,这时候他们都只能拿到自己的间隙锁,拿不到另外一个间隙锁,就进入了互相等待的死锁环节。

间隙锁产生的原因或者说作用

间隙锁的出现是为了在innodb的可重复读隔离级别下,解决幻读问题产生的。

间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据;所谓间隙是将数据分为不同区间,对该区间范围进行加锁,区间的规则为左开右闭,比如当数据为1,3,5时,对应的区间为(-∞,1],(1,3],(3,5],(5,+∞];

他这个行锁+间隙锁就组成了next---key lock,innodb在可重复度隔离级别下,采用next-key lock来防止幻读,因此实现了最高的隔离级别。

可能产生间隙锁的位置

对于操作的数据是主键索引和普通索引,有不同的加锁规则,如下:

1)、唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁;

2)、普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;

解决方案

①降低事务级别至读已提交(不推荐)

②先判断有无数据,有数据删,无数据则不删,因为删除不存在的数据一定会加间隙锁

③间隙锁非互斥锁,只针对写锁,只要两个线程锁定的区间有交叉就会出现死锁。可以根据条件查出所有主键,根据主键删除数据,这样只会加行锁而不是间隙锁(推荐)

④你如果把隔离级别设置为读提交的话,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row。如果读提交隔离级别够用,也就是说,业务不需要可重复读的保证,这样考虑到读提交下操作数据的锁范围更小(没有间隙锁),这个选择是合理的。

相关推荐
l1t23 分钟前
用Lua访问DuckDB数据库
数据库·junit·lua·duckdb
星空露珠24 分钟前
数独生成题目lua脚本
数据结构·数据库·算法·游戏·lua
deephub37 分钟前
构建有记忆的 AI Agent:SQLite 存储 + 向量检索完整方案示例
数据库·人工智能·sqlite·大语言模型·向量检索·智能体
无敌最俊朗@41 分钟前
SQlite:列级,表级约束
数据库
不剪发的Tony老师3 小时前
Mathesar:一款基于PostgreSQL的在线电子表格
数据库·postgresql·电子表格
万邦科技Lafite6 小时前
京东按图搜索京东商品(拍立淘) API (.jd.item_search_img)快速抓取数据
开发语言·前端·数据库·python·电商开放平台·京东开放平台
金仓拾光集6 小时前
__金仓数据库平替MongoDB实战:从多模兼容到高可用落地__
数据库·mongodb·数据库平替用金仓·金仓数据库
北邮-吴怀玉6 小时前
6.1.2.2 大数据方法论与实践指南-离线任务SQL 任务开发规范
大数据·数据库·sql
流烟默6 小时前
MongoDB索引创建语法分析
数据库·mongodb
金仓拾光集6 小时前
__国产化转型实战:制造业供应链物流系统从MongoDB至金仓数据库迁移全指南__
数据库·mongodb·数据库平替用金仓·金仓数据库