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

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

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

相关推荐

##&nbsp;一面&nbsp;1.&nbsp;自我介绍2.&nbsp;Java包装类,默认值3.&nbsp;Java中的值传递4.&nbsp;反射的定义等5.&nbsp;策略模式,有哪些角色6.&nbsp;策略与spring中容器结合:我说了ioc根据名字获取7.&nbsp;spring可以注入list结构吗1.&nbsp;是可以的,注入父接口8.&nbsp;怎么干预bean的生命周期9.&nbsp;bean后置处理和工厂后置处理的区别10.&nbsp;spring事务及失效场景11.&nbsp;CAS,公平锁,非公平锁12.&nbsp;ThreadLocal13.&nbsp;springboot&nbsp;start怎么定义14.&nbsp;接口比较慢的原因:15.&nbsp;数据库,锁&nbsp;for&nbsp;update16.&nbsp;可重复读及实现17.&nbsp;设计索引18.&nbsp;分布式锁的场景##&nbsp;二面1.&nbsp;AI在公司的应用2.&nbsp;AI中最大的挑战3.&nbsp;项目:排行榜的设计4.&nbsp;数据量大之后有什么挑战1.&nbsp;合并写5.&nbsp;redis使用场景和数据结构6.&nbsp;分布式锁原理,什么场景使用分布式锁7.&nbsp;除了redis,zookeeper之外的实现方式8.&nbsp;mysql和redis实现分布式锁的区别1.&nbsp;应该是没区别,性能区别呗9.&nbsp;项目兑换码设计10.&nbsp;优惠卷怎么推荐的11.&nbsp;并发性能的优化1.&nbsp;我说了一整个链路的12.&nbsp;缓存的原则(什么时候使用,读多写少)13.&nbsp;设计模式:策略&amp;观察者14.&nbsp;spring是事件机制,应该是想问*ApplicationEvent*15.&nbsp;mysql索引16.&nbsp;联合索引,最左匹配17.&nbsp;explain18.&nbsp;算法:最长递增子数组1.&nbsp;问我优化,忘了19.&nbsp;优缺点20.&nbsp;反问1.&nbsp;上班时间##&nbsp;三面1.&nbsp;快排2.&nbsp;做一个框架,什么设计模式被用到3.&nbsp;问了模板方法4.&nbsp;装饰器5.&nbsp;观察者6.&nbsp;jvm内存区域7.&nbsp;类定义是共享的吗8.&nbsp;索引,B+树,b树9.&nbsp;事务的定义10.&nbsp;隔离级别,mvcc11.&nbsp;串行化-&nbsp;**读操作**会加共享锁(S锁),阻止其他事务写入相同数据。-&nbsp;**写操作**会加排他锁(X锁),阻止其他事务读取或写入相同数据。-&nbsp;范围查询会加**间隙锁(Gap&nbsp;Lock)**,防止其他事务在范围内插入新记录,从而彻底消除幻读。在执行过程中,事务必须等待前一个事务释放锁才能继续,这种方式牺牲了并发性能,但换来了最强的数据一致性保障。12.&nbsp;操作系统1.&nbsp;信号量13.&nbsp;蛋糕切三刀,有多少块1.&nbsp;没答出来,我没招了14.&nbsp;幂等,http哪些请求是幂等,get,post这些吧15.&nbsp;ES(项目相关)16.&nbsp;数据一致性(最终一致)17.&nbsp;分布式事务18.&nbsp;反问1.&nbsp;应届生培养计划
点赞 评论 收藏
分享
评论
4
16
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务