间隙锁(Gap Lock)

一.什么是间隙锁

间隙锁(Gap Lock):当我们用范围条件而不是相等条件索引数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”。间隙锁Gap Lock,左右都是开区间,间隙锁+行锁合称next-key lock,每个 next-key lock 是前开后闭区间。间隙锁和next-key lock的引入帮我们解决幻读问题。

二.间隙锁产生的条件

事务隔离级别为RR(可重复读),间隙锁是为了防止幻读
执行delete/update/select for update操作,且where条件中索引未命中(命中加行锁,没有索引加表锁)

三.间隙锁的危害

因为Query执行过程中通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,也造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。
间隙锁的引入,虽然解决了幻读的问题,但可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的。在数据库参数中, 控制间隙锁的参数是:innodb_locks_unsafe_for_binlog,这个参数默认值是OFF, 也就是启用间隙锁, 他是一个布尔值, 当值为true时表示disable间隙锁。但这个参数会影响到主从复制及灾难恢复, 这个防止间隙锁的方法还尚待商量。

四.解决方案

①降低事务级别至读已提交(不推荐)
②先判断有无数据,有数据删,无数据则不删,因为删除不存在的数据一定会加间隙锁
③间隙锁非互斥锁,只针对写锁,只要两个线程锁定的区间有交叉就会出现死锁。可以根据条件查出所有主键,根据主键删除数据,这样只会加行锁而不是间隙锁(推荐)
④你如果把隔离级别设置为读提交的话,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row。如果读提交隔离级别够用,也就是说,业务不需要可重复读的保证,这样考虑到读提交下操作数据的锁范围更小(没有间隙锁),这个选择是合理的。

猜你喜欢

转载自blog.csdn.net/qq_43985303/article/details/132354063