MySQL 不完全入门指南

由于 MySQL 的整个体系太过于庞大,文章的篇幅有限,不能够完全的覆盖所有的方面。所以我会尽可能的从更加贴进我们日常使用的方式来进行解释。

小白眼中的 MySQL

首先,对于我们来说,MySQL 是个啥?我们从一个最简单的例子来回顾一下。

这可能就是最开始大家认知中的 MySQL。那 MySQL 中是怎么处理这个查询语句的呢?换句话说,它是如何感知到这串字符串是一个查询语句的?它是如何感知到该去哪张表中取数据?它是如何感知到该如何取数据?

到目前为止,都不知道。接下来我们一步一补来进行解析。

连接池

首先,要去 MySQL 执行命令,肯定是需要连接上 MySQL 服务器的,就像我们通过「用户名」和「密码」登陆网站一样。所以,我们首先要认识的就是连接池

这种池化技术的作用很明显,复用连接,避免频繁的销毁、创建线程所带来的开销。除此之外,在这一层还可以根据你的账号密码对用户的合法性、用户的权限进行校验。

每一个连接都对应一个线程,「服务器」 和 「MySQL」 都一样,服务器的一个线程从服务器的连接池中取出一个连接,发起查询语句。MySQL 服务器的线程从连接池中取出一个线程,继续后续的流程。

那么后面的流程是啥呢?当然是分析 SQL 语句了。

继续阅读MySQL 不完全入门指南

MySQL 中删除的数据都去哪儿了?

不知道大家有没有想过下面这件事?

我们平时调用 DELETE 在 MySQL 中删除的数据都去哪儿了?

这还用问吗?当然是被删除了啊

那么这里又有个新的问题了,如果在 InnoDB 下,多事务并发的情况下,如果事务A删除了 id=1 的数据,同时事务B又去读取 id=1 的数据,如果这条数据真的被删除了,那 MVCC 拿啥数据返回给用户呢?

没错,这就需要了解一下 MySQL 的多版本并发的原理相关的东西,感兴趣的可以去看我之前写的[这篇文章]()。

所以,实际情况中,调用了 DELETE 语句删除的数据并不会真正的被物理删除,这条数据其实还在那,只不过被打上了一个标记,标记已删除

继续阅读MySQL 中删除的数据都去哪儿了?

MySQL 到底是如何做到多版本并发的?

之前的文章简单的介绍了 MySQL 的事务隔离级别,它们分别是:读未提交、读已提交、可重复读、串行化。这篇文章我们就来探索一下 MySQL 事务隔离级别的底层原理。

本篇文章针对 InnoDB 存储引擎

多版本并发控制

我们知道,读未提交会造成脏读、幻读、不可重复读,读已提交会造成幻读、不可重复读,可重复读可能会有幻读,和串行化就不会有这些问题。

那 InnoDB 到底是怎么解决这些问题的呢?又或者,你有没有想过造成脏读、幻读、不可重复读的底层最根本的原因是什么呢?

这就是今天要聊的主角——MVCC(Multi-Version Concurrent Controll),也叫多版本并发控制。InnoDB 是一个支持多事务并发的存储引擎,它能让数据库中的读-写操作能够并发的进行,避免由于加锁而导致读阻塞。

正是由于有了 MVCC,在事务B更新 id=1 的数据时,事务A读取 id=1 的操作才不会被阻塞。而不阻塞的背后则是不加锁的一致性读。那什么是一致性读?

继续阅读MySQL 到底是如何做到多版本并发的?

啥是 MySQL 事务隔离级别?

之前发过一篇文章,简单了解 MySQL 中相关的锁,里面提到了,如果我们使用的 MySQL 存储引擎为 InnoDB ,并且其事务隔离级别是 RR 可重复读的话,是可以避免幻读的。

但是没想到,都 1202 年了都还有人杠,说 InnoDB 的 RR 隔离级别下会出现幻读,只能依靠 gap 和 next-key 这两个锁来防止幻读 ,最开始我还以为是他真的不知道这个点,就跟他聊,最后聊下来发现,发现是在钻牛角尖。

这个在下面讲到 可重复读 的隔离级别时会讲。

本来我觉得事务隔离级别这玩意儿太简单没啥可讲的,但是经过了上面这件事,我打算详细的把事务隔离给讲讲。接下来顺便就把 InnoDB 所有的事务隔离级别给搂一遍。

ACID

在聊事务隔离级别之前,我们需要知道 ACID 模型。

ACID 模型

分别代表:

继续阅读啥是 MySQL 事务隔离级别?

ArrayList 从源码角度剖析底层原理

对于 ArrayList 来说,我们平常用的最多的方法应该就是 addremove 了,本文就主要通过这两个基础的方法入手,通过源码来看看 ArrayList 的底层原理。

add

默认添加元素

这个应该是平常用的最多的方法了,其用法如下。

接下来我们就来看看 add 方法的底层源码。

ensureCapacityInternal 作用为:保证在不停的往 ArrayList 插入数据时,数组不会越界,并且实现自动扩容。

继续阅读ArrayList 从源码角度剖析底层原理

NameServer 核心原理解析

之前的文章中,已经把 Broker、Producer 和 Conusmer 的部分源码和核心的机制介绍的差不多了,但是其实 RocketMQ 中还有一个比较关键但是我们平时很容易忽略的组件——NameServer

在日常的使用中,我们接触的最多的还是 Producer 和 Consumer,而 NameServer 没有直接跟我们有交互。就像 Kafka 集群背后用于其集群元数据管理的 Zookeeper 集群一样,NameServer 也在背后支撑着 RocketMQ 正常工作。

你给翻译翻译,什么叫 NameServer

NameServer 你可以简单的把它理解成注册中心

Broker 启动的时候会将自己注册到 NameServer 中,注册的同时还会将 Broker 的 IP 地址、端口相关的数据,以及保存在 Broker 中的 RocketMQ 集群路由的数据一并跟随心跳发送到 NameServer。这里的路由信息是指 Topic 下的 MessageQueue 分别都在哪台 Broker 上。

Producer 则会从 NameServer 中获取元数据,从而将 Message 发到对应的 Broker 中去。

继续阅读NameServer 核心原理解析

InnoDB 表空间

这应该是 MySQL 原理中最底层的部分了,我们存在 MySQL 中的数据,到底在磁盘上长啥样。你可能会说,数据不都存储在聚簇索引中吗?但很遗憾,你并没有回答我的问题。我会再问你,那聚簇索引在磁盘上又长啥样?

就像 Redis 的 RDB 文件,最终落在磁盘上就是一个真真切切的 dump.rdb 文件,而 MySQL 就显得有点迷,我们只知道通过 SQL 去拿数据,并不知道数据最终是以什么方式进行存储的。当然,了解其底层的存储逻辑,并不仅仅是为了满足好奇心这么简单。

其底层的存储方式,会影响到聚簇索引中数据的存储,进而影响到 MySQL 的 DML(Data Manipulation Language) 性能,所以对底层存储逻辑有个清晰的认知,就能够在某些对性能有着极致追求的场景下,帮助我们对 MySQL 进行优化。

表在磁盘上到底长啥样

继续阅读InnoDB 表空间

MySQL 页完全指南——浅入深出页的原理

之前写了一些关于 MySQL 的 InnoDB 存储引擎的文章,里面好几次都提到了页(Pages)这个概念,但是都只是简要的提了一下。例如之前在聊 InnoDB内存结构 时提到过,但当时的重点是内存架构,就没有展开深入。

我发现有好几次都需要提到页,那我就正好拿一篇来详细的讲讲 InnoDB 中的页。

页是什么

首先,我们需要知道,页(Pages)是 InnoDB 中管理数据的最小单元。Buffer Pool 中存的就是一页一页的数据。再比如,当我们要查询的数据不在 Buffer Pool 中时,InnoDB 会将记录所在的页整个加载到 Buffer Pool 中去;同样的,将 Buffer Pool 中的脏页刷入磁盘时,也是按照页为单位刷入磁盘的。

不了解 Buffer Pool 的、或者感兴趣的可以去文章开头给的链接熟悉一下

页的概览

我们往 MySQL 插入的数据最终都是存在页中的。在 InnoDB 中的设计中,页与页之间是通过一个双向链表连接起来。

而存储在页中的一行一行的数据则是通过单链表连接起来的。

继续阅读MySQL 页完全指南——浅入深出页的原理

缓存与数据库的双写一致性

这几天瞎逛,不知道在哪里瞟到了缓存的双写,就突然想起来这块虽然简单,但是细节上还是有足够多我们可以去关注的点。这篇文章就来详细聊聊双写一致性

首先我们知道,现在将高速缓存应用于业务当中已经十分常见了,甚至可能跟数据库的频率不相上下。你的用户量如果上去了,直接将一个裸的 MySQL 去扛住所有压力明显是不合理的。

这里的高速缓存,目前业界主流的就是 Redis 了,关于 Redis 相关的文章,之前也有聊过,在此就不赘述,感兴趣的可以看看:

额,不列出来我都没感觉关于 Redis 我居然写了这么多…言归正传。

在我们的业务中,普遍都会需要将一部分常用的热点数据(或者说不经常变但是又比较多的数据)放入 Redis 中缓存起来。下次业务来请求查询时,就可以直接将 Redis 中的数据返回,以此来减少业务系统和数据库的交互。

这样有两个好处,一个是能够降低数据库的压力,另一个自不必说,对相同数据来说能够有效的降低 API 的 RT(Response Time)。

继续阅读缓存与数据库的双写一致性

深入剖析 MySQL 自增锁

之前的文章把 InnoDB 中的所有的锁都介绍了一下,包括意向锁、记录锁…自增锁巴拉巴拉的。但是后面我自己回过头去看的时候发现,对自增锁的介绍居然才短短的一段。

其实自增锁(AUTO-INC Locks)这块还是有很多值得讨论的细节,例如在并发的场景下,InnoDB 是如何保证该值正确的进行自增的,本章就专门来简单讨论一下 InnoDB 中的自增锁。

什么是自增锁

之前我们提到过,自增锁是一种比较特殊的表级锁。并且在事务向包含了 AUTO_INCREMENT 列的表中新增数据时就会去持有自增锁,假设事务 A 正在做这个操作,如果另一个事务 B 尝试执行 INSERT语句,事务 B 会被阻塞住,直到事务 A 释放自增锁。

这怎么说呢,说他对,但是他也不完全对。

继续阅读深入剖析 MySQL 自增锁