阿里面试官:MySQL的InnoDB引擎是如何解决幻读问题的?(上)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 阿里面试官:MySQL的InnoDB引擎是如何解决幻读问题的?

SQL准备

image.png

主键id,索引c。

  • 下面的语句怎么加锁,何时释放?
  • image.png
  • 该语句会命中d=5一行,对应主键id=5。
    因此在select 语句执行完后,id=5一行会加写锁。因两阶段锁协议,写锁会在执行commit语句时释放。

由于字段d无索引,该查询语句会全表扫描。其他被扫到但不满足条件的5行记录会不会被加锁呢?

InnoDB默认事务隔离级别可重复读。

幻读

若只在id=5一行加锁,而其他行不加锁:

  • 假设只在id=5一行加行锁
  • image.png
  • session A执行三次查询-Q1、Q2和Q3,SQL语句相同:查所有d=5的行,且使用当前读并加写锁。

Q1只返回id=5一行

T2时,session B把id=0一行的d值改成5,因此T3时Q2查出来的是id=0和id=5这两行

T4时,session C插入(1,1,5),因此T5时Q3查出来的是id=0、id=1和id=5的三行

Q3读到id=1这一行称为“幻读”,即一个事务在前后两次查询同一范围时,后一次查询看到前一次查询没看到的行。

在可重复读下,普通查询是快照读,不会看到别的事务插入的数据。因此,幻读在“当前读”下才会出现。

session B的修改结果,被session A之后的select语句用“当前读”看到,不能称为幻读。幻读仅专指新插入的行。


这三查询都加了for update,都是当前读。当前读就是要能读到所有已提交的记录的最新值。

session B和sessionC的两条语句,执行后就会提交,所以Q2和Q3就应该看到这俩事务的操作效果,所以这和事务的可见性不矛盾。

但这真的没问题?

不,这里还真有问题。

幻读的问题

语义问题

session A在T1时刻就声明了,“我要把所有d=5的行锁住,不准别的事务进行读写操作”。而实际上,这个语义被破坏了。

再往session B和session C里面分别加一条SQL语句,你再看看会出现什么现象。

  • 假设只在id=5这行加行锁 - 语义被破坏
  • image.png
  • session B的第二条语句update t set c=5 where id=0,由于在T1,session A 还只是给id=5这行加行锁, 并未给id=0这行加锁。

因此,session B在T2,可执行这两条update。这就破坏了 session A 里Q1语句要锁住所有d=5的行的加锁声明。

同理,session C对id=1这行的修改,也是破坏了Q1的加锁声明。

数据一致性问题

锁是为了保证数据一致性。而这个一致性,不止是DB内部数据状态在此刻的一致性,还包含数据和日志在逻辑上的一致性。

我给session A在T1时刻再加一个更新语句,即:update t set d=100 where d=5。

  • 假设只在id=5这一行加行锁 - 数据一致性问题
  • image.png
  • update的加锁语义和select …for update 一致,所以这时加上这条update语句也很合理。session A声明说“要给d=5的语句加锁”,就是为更新数据,新加的这条update语句就是把它认为加上锁的这行d值修改成了100。


以上序列执行完成后,DB结果是啥呢?


T1后,id=5这行变成 (5,5,100),该结果最终在T6时刻正式提交

T2后,id=0这行变成(0,5,5)

T4后,表里多了行(1,5,5)

其他行跟该执行序列无关,保持不变。


这样看,这些数据也没啥问题,但再看binlog:


T2,session B事务提交,写入两条语句

T4,session C事务提交,写入两条语句

T6,session A事务提交,写入update t set d=100 where d=5 语句。

放到一起:

update t set d=5 where id=0; /*(0,0,5)*/
update t set c=5 where id=0; /*(0,5,5)*/
insert into t values(1,1,5); /*(1,1,5)*/
update t set c=5 where id=1; /*(1,5,5)*/
update t set d=100 where d=5;/*所有d=5的行,d改成100*/

这个语句序列,不论是拿到备库去执行,还是以后用binlog来克隆一个库,这三行结果都变成了 (0,5,100)、(1,5,100)和(5,5,100)。

即id=0和id=1这两行,发生数据不一致!

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
15天前
|
SQL 关系型数据库 MySQL
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
MySQL慢查询优化、索引优化,是必知必备,大厂面试高频,本文深入详解,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
|
2月前
|
存储 关系型数据库 MySQL
阿里面试:为什么要索引?什么是MySQL索引?底层结构是什么?
尼恩是一位资深架构师,他在自己的读者交流群中分享了关于MySQL索引的重要知识点。索引是帮助MySQL高效获取数据的数据结构,主要作用包括显著提升查询速度、降低磁盘I/O次数、优化排序与分组操作以及提升复杂查询的性能。MySQL支持多种索引类型,如主键索引、唯一索引、普通索引、全文索引和空间数据索引。索引的底层数据结构主要是B+树,它能够有效支持范围查询和顺序遍历,同时保持高效的插入、删除和查找性能。尼恩还强调了索引的优缺点,并提供了多个面试题及其解答,帮助读者在面试中脱颖而出。相关资料可在公众号【技术自由圈】获取。
|
19天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
129 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
1月前
|
SQL 缓存 关系型数据库
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴因未能系统梳理MySQL缓存机制而在美团面试中失利。为此,尼恩对MySQL的缓存机制进行了系统化梳理,包括一级缓存(InnoDB缓存)和二级缓存(查询缓存)。同时,他还将这些知识点整理进《尼恩Java面试宝典PDF》V175版本,帮助大家提升技术水平,顺利通过面试。更多技术资料请关注公号【技术自由圈】。
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
|
19天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的表空间
InnoDB是MySQL默认的存储引擎,主要由存储结构、内存结构和线程结构组成。其存储结构分为逻辑和物理两部分,逻辑存储结构包括表空间、段、区和页。表空间是InnoDB逻辑结构的最高层,所有数据都存放在其中。默认情况下,InnoDB有一个共享表空间ibdata1,用于存放撤销信息、系统事务信息等。启用参数`innodb_file_per_table`后,每张表的数据可以单独存放在一个表空间内,但撤销信息等仍存放在共享表空间中。
|
19天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的段、区和页
MySQL的InnoDB存储引擎逻辑存储结构与Oracle相似,包括表空间、段、区和页。表空间由段和页组成,段包括数据段、索引段等。区是1MB的连续空间,页是16KB的最小物理存储单位。InnoDB是面向行的存储引擎,每个页最多可存放7992行记录。
|
17天前
|
SQL 关系型数据库 MySQL
阿里面试:1000万级大表, 如何 加索引?
45岁老架构师尼恩在其读者交流群中分享了如何在生产环境中给大表加索引的方法。文章详细介绍了两种索引构建方式:在线模式(Online DDL)和离线模式(Offline DDL),并深入探讨了 MySQL 5.6.7 之前的“影子策略”和 pt-online-schema-change 方案,以及 MySQL 5.6.7 之后的内部 Online DDL 特性。通过这些方法,可以有效地减少 DDL 操作对业务的影响,确保数据的一致性和完整性。尼恩还提供了大量面试题和解决方案,帮助读者在面试中充分展示技术实力。
|
20天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL的InnoDB存储引擎
InnoDB是MySQL的默认存储引擎,广泛应用于互联网公司。它支持事务、行级锁、外键和高效处理大量数据。InnoDB的主要特性包括解决不可重复读和幻读问题、高并发度、B+树索引等。其存储结构分为逻辑和物理两部分,内存结构类似Oracle的SGA和PGA,线程结构包括主线程、I/O线程和其他辅助线程。
【赵渝强老师】MySQL的InnoDB存储引擎
|
24天前
|
SQL 算法 关系型数据库
面试:什么是死锁,如何避免或解决死锁;MySQL中的死锁现象,MySQL死锁如何解决
面试:什么是死锁,死锁产生的四个必要条件,如何避免或解决死锁;数据库锁,锁分类,控制事务;MySQL中的死锁现象,MySQL死锁如何解决
|
1月前
|
SQL 关系型数据库 MySQL
美团面试:Mysql如何选择最优 执行计划,为什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴面试美团时遇到了关于MySQL执行计划的面试题:“MySQL如何选择最优执行计划,为什么?”由于缺乏系统化的准备,小伙伴未能给出满意的答案,面试失败。为此,尼恩为大家系统化地梳理了MySQL执行计划的相关知识,帮助大家提升技术水平,展示“技术肌肉”,让面试官“爱到不能自已”。相关内容已收录进《尼恩Java面试宝典PDF》V175版本,供大家参考学习。