阿里二面:了解 MySQL 事务底层原理吗(一)

Hunter37
发布于 2022-5-27 17:42
浏览
0收藏

 

你好,我是坤哥,今天是国庆最后一天,不知大家是否玩得尽兴,我基本在家带娃了,累得半死,顺带肝了一篇文,来自读者曾经在阿里的面试题,希望对大家有帮助,另外也欢迎大家加我微信「geekoftaste」,一起探讨技术问题,有疑问的我也许可以帮上忙^_^

 

MySQL 可以说是每个 Java 程序员必会的技能之一,作为 Java 的高级进阶必备技能点,MySQL 的调优和底层原理必然是需要知道的。

 

但是大家似乎形成了一种思维定势,那就是提到 MySQL 好像就一股脑的往 MySQL 的索引啊、优化啊、之类的上面去钻。本文我们抛开“热门”的话题,来和大家一起来聊一聊比较冷门但比较重要的技术点:MySQL 事务的底层原理

 

这事情还得从头说起

 

首先大家需要知道的是 MySQL 是支持事务并发执行的,这又回到了最原始的问题了,「并发安全性问题」。在数据库事务中并发问题是这样子的:A 事务来写某条记录的数据,B 事务也在写该条记录的数据。那如果啥也不做,势必会造成数据的错乱,MySQL 在设计之初就考虑到了这个问题。

 

那么 MySQL 到底是如何解决这样的问题的呢?其实是使用了 MVCC 多版本控制机制、事务隔离机制、锁机制等办法来解决事务并发问题。那说到这里不知道各位有没有想过这样一个问题:在数据库中如果并发事务不做控制和处理,会有什么样的危害呢?

 

带着这样的疑问,请继续往下看。

 

脏数据

 

什么是脏数据,它有哪些类型

 

脏数据的具体概念有以下四种,分别是:脏写、脏读、不可重复读、幻读。我们来看看这几个概念的意思

 

1、脏写


脏写是指一个事务修改且已经提交的数据被另外一个事务给回滚了


首先来分析一下概念:假设有两个事务 A、B。事务 A 先开启事务,并且修改了一条 id 为 1 的记录,将 name 改成  A(假设原来为 null),但是此时 事务 A 还没有提交。这个时候事务 B 开启了。事务 B 将 id 为 1 的记录中 name 改成了 B,并且将事务提交 了。但是这个时候事务 A 不想修改了,就像之前自己修改的数据回滚了。也就是说此时导致的结果就是 id 为 1 的这条记录的 name 还是为 null。

 

然后事务 B 去查询这条记录。结果蒙了。name 居然为 null。这就是脏写。事务 B 已经写入的记录被事务 A 给回滚了。

 

看不懂没有关系,我们先来看一张图

 阿里二面:了解 MySQL 事务底层原理吗(一)-鸿蒙开发者社区
对着图再来看一下上面的分析过程。

 

那 MySQL 是如何来解决脏写这种问题的?没错,就是。MySQL 在开启一个事务的时候,他会将某条记录和事务做一个绑定。这个其实和 JVM 锁是类似的。因为此时事务 A 先开启了,并关联绑定了这条记录。所以事务 B 此时如果想操作同样的记录,只能等待。当事务 A 执行完成了,就会通知正在等在事务。然后下一个事务继续操作执行。

 

啥?说好的并发,这说到底不还是串行吗?这样数据库岂不是慢的要死。实际上这些操作都是在内存中执行的。具体一点是在 Buffer Pool 中执行的。所以速度是非常快的。

 

2、脏读


脏读是指一个事务读取到了另外一个事务没有提交的记录


其实脏读是最好理解的。我们还是假设有两个事务 A、B。事务 A 先开启了,将 id 为 1 的记录中的 name 改成了 A,但是还没有提交。此时事务 B 开启了。事务 B 查询到当前 name 的值为 A,然后就会按照 A 逻辑去执行处理。结果事务 A 回滚了事务,事务 B 再次查询的时候发现记录值不是 A。这就是脏读。

 

事务 B 读取到的 name 值是事务 A 修改但是没有提交的记录。

来张图来直观的理解下:

 阿里二面:了解 MySQL 事务底层原理吗(一)-鸿蒙开发者社区
3、不可重复读


不可重复读是指前后读取到的某条记录的结果不一样


废话少说,直接进分析:假设有三个事务 A、B、C ,事务 A 先开启了,但是还没有执行任何的操作,事务 B 开启了,事务 B 将 id 为 1 的记录的 name 改为 B 并提交了事务,此时事务 A 开始活动了,查询到的这条记录的 name 值为 B,还是还未执行任何操作。此时事务 C 开启了,事务 C 将 id 为 1 的记录的 name 改为 C 并提交了事务。此时事务 A 又开始活动了,结果查询到的 id 为 1 的 name 值又变成了 C。这就是不可重复读

 

其实理解起来还是很简单的。看起来高大上名字,实际上就这么几句话就能描述结束了。下面还是来一张图来更直观认识下:

 阿里二面:了解 MySQL 事务底层原理吗(一)-鸿蒙开发者社区
4、幻读


幻读是指前后读取到的记录的数量不一样


幻读和不可重复读有点类似,不可重复读强调的是数据的值不一样,重点是修改,而幻读强调的是记录的数量不一样,重点是新增或删除。就好像是看花眼产生重影一样。

 

先来分析一下幻读。还是假设有两个事务 A、B。事务 A 先开启了,并执行了这样的 SQL:select *  from user,假设现在结果是 5 条,此时事务 B 开启了,并往 user 表中插入了一条记录,并提交了事务,此时事务 A 又执行了  select *  from user结果发现是 6 条记录。懵逼了。还以为自己饿昏了眼花了。这就是所谓的幻读。

 阿里二面:了解 MySQL 事务底层原理吗(一)-鸿蒙开发者社区
以上的四个问题是现代数据库典型的问题,这些问题会在不同的数据库的事务隔离级别下产生。所以下面要分析的就是事务的隔离级别。

 

事务的隔离级别


事务的隔离级别有以下四种

 

  1. Read Uncommitted:读取未提交【生产估计没人这么设置的】
    意思就是一个事务能够读取到另一个事务未提交的修改
  2. Read Committed[简称 RC]:读取已提交
    意思就是一个事务能读取到另一个事务已经提交了的修改
  3. Repeatable read[简称 RR]:可重复读
    【MySQL 的默认隔离级别】,即事务之间只要是在进行中,彼此之间不会有任何的干扰
  4. serializable:串行化
    这个就有点狠了,就好比 Java 中的 synchroinzed 关键字,所有的请求只能一个一个来还行,很显然效率最低,基本也不会使用这种隔离剂呗


阿里二面:了解 MySQL 事务底层原理吗(一)-鸿蒙开发者社区

文章转自公众号:码海

分类
标签
已于2022-5-27 17:42:09修改
收藏
回复
举报
回复
    相关推荐