MVCC机制和间隙锁

MVCC机制:多版本并发控制,通过保留数据的多个版本来提高并发性能。隔离级别:可重复读

核心实现原理

  • 隐藏字段:给每行数据加了2个隐藏字段【最后一次修改该行的事务id和指向改行历史版本的回滚指针
  • undo log(回滚日志):记录了修改之前的数据内容【注意与RedoLog区别,一个是记录修改前,一个是记录修改后。回滚和持久化】
  • Read View(读视图):ReadView是MVCC中用于定义事务可见性的机制。每个事务在开始时会生成一个ReadView,ReadView决定了哪些版本的数据对该事务可见。ReadView包含以下关键信息:
  • m_ids:当前活跃(未提交)的事务ID集合。
  • min_trx_id:活跃事务中的最小事务ID。
  • max_trx_id:下一个将要分配的事务ID。
  • creator_trx_id:创建该ReadView的事务ID。
  • 通过ReadView,事务可以判断某行数据的版本是否可见:

  • 如果数据版本的事务ID小于min_trx_id,则该版本对当前事务可见。
  • 如果数据版本的事务ID在m_ids中,则该版本对当前事务不可见。
  • 如果数据版本的事务ID大于max_trx_id,则该版本对当前事务不可见。

Repeatable Read隔离级别下,MVCC可以避免快照读中的幻读问题。然而,如果事务中存在当前读操作(如SELECT ... FOR UPDATE),仅靠MVCC是不够的,还需要锁机制来防止其他事务插入新数据。

(1) 间隙锁(Gap Lock)

间隙锁锁定的是索引记录之间的“间隙”,防止其他事务在范围内插入新数据。例如,表中现有记录的age值为[10, 20, 30],执行SELECT * FROM users WHERE age > 20 FOR UPDATE时,InnoDB会锁定(20, +∞)的区间。

(2) 临键锁(Next-Key Lock)

临键锁是**记录锁(Record Lock) + 间隙锁(Gap Lock)**的组合,锁定索引记录及其之前的间隙。例如,索引值为20的记录,临键锁会锁定区间(-∞, 20]

SELECT * FROM Users WHERE age < 20 FOR UPDATE;
  • 记录锁:锁定age = 10的记录。【有记录为10的行】
  • 间隙锁:锁定age = 10和age = 20之间的间隙。
  • 临键锁:锁定(-∞, 20)范围内的所有记录和间隙。

3. 如何解决幻读

当执行范围查询并请求共享或排他锁时(如SELECT ... FOR UPDATE),InnoDB会给符合条件的已有数据记录的索引项加锁,同时也会对键值在条件范围内但并不存在的记录(即间隙)加锁。这样,其他事务就无法在这个范围内插入新的数据,从而避免了幻读问题。

例如:

  1. 事务A执行:SELECT * FROM users WHERE age > 20 FOR UPDATE,InnoDB会通过临键锁锁定age > 20的范围。
  2. 事务B尝试插入:INSERT INTO users (age) VALUES (25),该操作会被阻塞,直到事务A提交或回滚。
  3. 因此,事务A的两次查询结果一致,避免了幻读。

4. 注意事项

  • 仅对当前读有效:MVCC的快照读可以避免幻读,但若事务中混合快照读和当前读,仍需显式加锁。
  • 索引依赖:间隙锁和临键锁依赖于索引。若查询未使用索引,InnoDB会退化为表锁,严重影响性能。
  • 隔离级别限制:在Read Committed隔离级别下,间隙锁会被禁用,无法完全避免幻读。

总结

InnoDB通过MVCC的快照读临键锁的当前读双重机制,在Repeatable Read隔离级别下解决了幻读问题:

  • MVCC:保证快照读的一致性视图。
  • 临键锁:通过锁定索引范围,阻止其他事务插入新数据。

理解这些机制有助于在实际开发中合理设计事务和查询逻辑,确保数据一致性并提升并发性能。

全部评论
其实你写的这些是详细原理 当年总结一个回答模版吗
点赞 回复 分享
发布于 02-23 13:44 广东

相关推荐

04-22 01:38
复旦大学 Java
快手电商一面&nbsp;55分钟&nbsp;4.81.&nbsp;自我介绍2.&nbsp;实习的难点,怎么解决的3.&nbsp;实习的收获4.&nbsp;ArrayList和LinkedList&nbsp;&nbsp;ArrayList线程安全吗&nbsp;&nbsp;具体不安全在哪5.&nbsp;hashMap的put流程6.&nbsp;hashMap扩容&nbsp;hash值会变吗7.&nbsp;谈谈并发&nbsp;synchronized和reentrantlock的区别8.&nbsp;线程池执行任务的过程9.&nbsp;线程池的线程怎么被销毁的,超时销毁的原理10.&nbsp;java中的基本类型&nbsp;int的范围&nbsp;char的范围11.&nbsp;浮点型&nbsp;0.1+0.2&nbsp;==&nbsp;0.3?为什么?所有小数都不准吗?什么时候准?12.&nbsp;MySQL一张表的大小一般多大13.&nbsp;ABC索引&nbsp;AB&nbsp;AC&nbsp;BC用到哪些14.&nbsp;消息队列怎么保证消息不丢15.&nbsp;Redis的大key是什么?&nbsp;为什么大Key不好?16.&nbsp;linux常用命令&nbsp;要查某个日志的前4行和最后4行怎么做17.&nbsp;算法:排序链表删除重复数字,要求两个样例通过。二面&nbsp;4.11&nbsp;&nbsp;40分钟1.自我介绍2.介绍项目/实习中觉得做的最好的、最有成就感的模块。有没有参考开源框架。3.&nbsp;&nbsp;系统设计:直播间打榜榜单排名系统。要求:一个直播间50w用户,存在上万个直播间。考虑并发问题。4.MySQL可重复读隔离级别怎么解决幻读的5.为什么还会发生幻读,间隙锁不起作用吗6.&nbsp;&nbsp;临键锁的退化了解吗7.&nbsp;&nbsp;算法:给定一棵树,按后序遍历的顺序转双向链表。要求代码跑通过,时间复杂度和空间复杂度低。评价:学生看问题还是太浅了,不要仅仅局限于使用设计模式什么的,多看看大型开源框架是怎么做的。
查看24道真题和解析
点赞 评论 收藏
分享
评论
4
15
分享

创作者周榜

更多
牛客网
牛客企业服务