首页 > 数据库 >MySQL 通过 Next-Key Locking 技术(行锁+间隙锁)避免幻读问题

MySQL 通过 Next-Key Locking 技术(行锁+间隙锁)避免幻读问题

时间:2024-10-16 22:59:26浏览次数:7  
标签:事务 间隙 幻读 行锁 Locking Next Key 查询

在MySQL中,InnoDB引擎通过Next-Key Locking技术来解决幻读问题。幻读是一种事务并发问题,通常出现在Repeatable Read隔离级别下的范围查询操作中。幻读的现象是,事务在查询时多次执行相同的范围查询,但由于其他事务的插入或删除操作导致结果不一致,出现“幻觉”一样的记录。

Next-Key Locking 技术结合了 行锁(Record Lock)间隙锁(Gap Lock),通过锁定范围内的记录和它们之间的间隙,防止其他事务在这些锁定的区域内插入或删除数据,从而避免了幻读问题。

一、什么是Next-Key Locking?

Next-Key Locking 是一种 锁定区间 的机制,它由两部分组成:

  1. 行锁(Record Lock):锁定精确的一行数据,防止其他事务对该行数据的修改。
  2. 间隙锁(Gap Lock):锁定一行数据之间的“间隙”,防止其他事务在该间隙中插入新数据。

Next-Key Locking 锁住了当前查询的行及其“前后”的间隙,这样不仅可以防止已有记录的修改,还能防止在查询范围内插入新数据,避免了幻读问题。

二、Next-Key Locking 的原理

Repeatable Read隔离级别下,当执行范围查询时,InnoDB会通过Next-Key Locking在范围内锁定所有满足条件的行及其相邻的间隙。例如,执行下面的SQL语句:

SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE;

这个查询会锁定users表中所有满足age BETWEEN 20 AND 30的行,以及每一行数据之间的“间隙”。具体锁定机制如下:

  1. 行锁(Record Lock):锁定所有符合条件的行,阻止其他事务修改这些行。
  2. 间隙锁(Gap Lock):锁定查询范围内的行之间的“间隙”,阻止其他事务在这些间隙中插入新行。

假设当前数据如下:

id | age
---------
 1 | 18
 2 | 25
 3 | 28
 4 | 35

执行 SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE; 时,Next-Key Locking 会做如下操作:

  • 锁住 age=25age=28 这两行(Record Lock)。
  • 锁住age > 18age < 35 之间的所有间隙(Gap Lock),即阻止在 age=19age=34 之间插入新行。

这保证了在当前事务提交之前,其他事务无法在查询的范围内插入、删除或修改数据,从而避免了幻读。

三、Next-Key Locking 的实现机制

  1. Record Lock(行锁):行锁是一种精确的锁,它只会锁定某个特定的行,防止其他事务修改该行数据。行锁可以确保事务中的读写操作对已经存在的数据行保持一致。
  2. Gap Lock(间隙锁):间隙锁是一种范围锁,它锁定数据行之间的间隙。它不会锁定实际的数据行,而是锁定行之间的空隙,防止其他事务在这些空隙中插入新的记录。这种锁用来解决幻读问题。
  3. Next-Key Locking(行锁 + 间隙锁):Next-Key Locking 结合了行锁和间隙锁,它不仅锁住了精确的数据行,还锁住了数据行之间的间隙。这样,Next-Key Locking 能有效防止其他事务在当前查询的范围内插入新数据,从而避免幻读。

四、Next-Key Locking 解决幻读的过程

Next-Key Locking 是在Repeatable Read隔离级别中使用的,流程大致如下:

  1. 事务A执行一个范围查询,例如SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE;。此时,InnoDB 会使用 Next-Key Locking 锁住范围内的数据行和间隙,阻止其他事务在该范围内插入新的记录。
  2. 事务B尝试在age=26的位置插入一条新记录。由于事务A已经通过Next-Key Locking锁住了age=25age=30之间的间隙,事务B将被阻塞,直到事务A提交或回滚。
  3. 事务A提交或回滚后,事务B才能成功插入数据。如果事务A没有锁定这个范围,事务B插入数据后,事务A再进行范围查询时,结果就会不同,导致幻读的产生。

通过这种方式,Next-Key Locking 解决了由于并发插入导致的幻读问题。

五、Next-Key Locking 的优势与限制

优势

  • 解决幻读问题:Next-Key Locking 能有效防止在范围查询时产生幻读,保证事务的一致性。
  • 增强数据安全性:锁住查询范围内的间隙,防止其他事务在未提交的情况下对数据进行插入或修改,保证事务中的数据一致性。

限制

  • 降低并发性能:Next-Key Locking 的锁粒度较大,可能会锁定大量的行和间隙,导致系统的并发性能下降。
  • 间隙锁的开销:间隙锁会导致无法插入数据到锁定范围内的空隙中,这在某些场景下可能影响数据写入效率,尤其是在高并发写入的场景。

六、Next-Key Locking 的实际使用场景

  1. 银行系统中的余额查询
    • 在银行系统中,用户查询账户余额时可能会执行范围查询(例如,查询特定时间段的交易记录)。通过Next-Key Locking,系统可以防止其他事务在这个时间段内插入新的交易记录,确保用户每次查询得到的一致结果。
  2. 电商系统中的订单查询
    • 在电商平台中,用户查询某一时间段的订单时,可能需要保证查询过程中订单数据的一致性。通过Next-Key Locking,避免其他用户在订单查询期间插入新的订单,确保订单数据的一致性。

七、总结

Next-Key Locking 通过将行锁和间隙锁结合起来,解决了MySQL中Repeatable Read隔离级别下的幻读问题。它不仅锁住了查询范围内的具体数据行,还锁住了数据行之间的空隙,防止了新数据的插入。虽然这种锁机制能有效解决并发环境下的数据一致性问题,但也会带来并发性能的下降,需要在实际业务场景中权衡使用。
看了那么久别人写的内容,自己整理,总结归纳一下。言简意赅

标签:事务,间隙,幻读,行锁,Locking,Next,Key,查询
From: https://www.cnblogs.com/lgx211/p/18471125

相关文章

  • MySQL 行锁
    InnoDB和MyISAM对比Innodb支持崩溃恢复InnoDB支持事务InnoDB支持行锁B+Tree叶子节点存储内容不同MyISAM记录表行总数,InnoDB没有两阶段锁InnoDB读操作会使用MVCC,而写操作会使用写锁。InnoDB两阶段锁协议:行锁是在需要的时候加上的,并且要等到事务提交后才释放......
  • 07 行锁功过:怎么减少行锁对性能的影响?
    Hello!欢迎各位新老朋友来看小弟博客,祝大家事业顺利,财源广进!!主题:MySQL的行锁在上一篇文章中,我跟你介绍了MySQL的全局锁和表级锁,今天我们就来讲讲MySQL的行锁。MySQL的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如MyISAM引擎就不支持......
  • Blocking Elements
    BlockingElements题目描述给定一个长度为\(n\)的序列\(A\),你需要划分这个序列。先任意选择若干个位置,假定你选择了\(m\)个位置,这些位置分别为\(B_1,B_2...B_m\),这一次划分的代价为下面两个量中的最大值:\(\sum\limits_{i=1}^{m}A_{B_{i}}\).\(\max\limits_{i=0}^{m}{......
  • 京东面试:RR隔离mysql如何实现?什么情况RR不能解决幻读?
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • 【VUE】[Violation] Added non-passive event listener to a scroll-blocking...
    1.问题[Violation]Addednon-passiveeventlistenertoascroll-blocking<某些>事件.Considermarkingeventhandleras'passive'tomakethepagemoreresponsive.See<URL>译:[违规]向滚动阻止添加了非被动事件侦听器<某些>事件.请考虑将事件处理程序标记为“被......
  • 【JUC并发编程系列】深入理解Java并发机制:阻塞队列详解与简单纯手写(七、BlockingQueu
    文章目录【JUC并发编程系列】深入理解Java并发机制:阻塞队列详解与简单纯手写(七、BlockingQueue、ArrayBlockingQueue、LinkedBlocking)1.简单回顾1.1数组结构和链表结构1.1.1数组结构1.1.2链表结构1.2有界队列与无界队列1.3Lock锁使用回顾2.什么是阻塞队列3.B......
  • BlockingQueue---DelayQueue
    总结一个无界阻塞队列;FIFO;只包含实现了Delayed接口的元素,每个元素都有一个延迟时间,在该延迟时间结束之前,该元素不会从队列中可用。一旦元素的延迟到期,它就可以被取出了,并且取出的顺序是按照延迟到期的时间先后进行的。通常用于实现定时任务调度、缓存过期等......
  • 脏读!幻读!不可重复读!mysql并发事务引发的问题
    脏读!幻读!不可重复读!mysql并发事务引发的问题并发事务引发的三个问题①脏读脏读(DirtyRead)是数据库事务隔离级别中的一种现象。它发生在两个事务并发执行时,一个事务能够读取到另一个事务尚未提交的修改。脏读的具体情况事务A对某个数据进行了修改,但尚未提交。事务B在事务......
  • BlockingQueue---PriorityBlockingQueue
    总结一个无界的并发队列。按照元素的优先级顺序来处理元素。这种队列非常适合需要按照优先级处理任务的场景。特性无界:默认情况下是无界的,可以存储任意数量的元素。基于优先级:队列中的元素根据它们的自然顺序或者由构造时提供的 Comparator 来排序。线程安全:支持......
  • Qt::BlockingQueuedConnection 与 QMetaCallEvent
    Qt创建连接类型如果是Qt::BlockingQueuedConnection,即senderthread与receiverthread不同,但是要求sendersignal与receiverslot执行是不同线程间的同步行为。也即:在sendersignal发出后sender线程要等待receiver线程的slot执行完后才能继续向后执行指令。......