• 学一个技术,我们先要 跳出来,看整体,先要在脑中有一个这个技术的全貌。然后再 钻进去,看本质,深入的研究细节。这样方便我们建立一个立体的知识网络。不然单学多个知识点,是串不起来的。不容易记住,理解也不会深刻。
  • 所以,我们先把 MySQL 拆解一下,看看内部有哪些组件,我们 Java系统执行一条SQL,MySQL的内部是如何运作,给我们返回结果的。
  • 我们先从我们访问数据库说起
    • 我们想要查询数据库,首先得建立网络连接
    • MySQL 驱动负责建立网络连接,然后请求 MySQL 数据库
    • 其实就是创建了一个数据库连接
  • Java系统的 数据库连接池
    • 如果我们的系统所有线程访问数据库时,都使用一个连接会怎样

      • 所有线程抢夺一个连接,没有连接 就操作不了数据库,效率极低,因为需要后面的线程需要等待前面的线程处理完才行
  • 我们的系统如果每个线程访问数据库时,都创建一个连接,然后销毁,会怎样
    • 创建连接需要网络通信,网络通信是很耗时的
    • 好不容易创建了连接,查询完就给销毁了,那效率肯定低
  • 所以,我们要使用数据库连接池
    • 数据库连接池里,会有多个数据库连接

      • 每个线程使用完连接后,会放回池子,连接不会销毁
      • 常用的数据库连接池有 DBCP、C3P0、Druid
  • MySQL 的 连接器
    • Java 系统要和MySQL 建立多个连接,那 MySQL 自然也需要维护与系统之间的连接

      • 所以,MySQL 整体架构的第一个组件就是 连接器
  • MySQL 连接器的功能
    • 连接器负责跟客户端建立连接、获取权限、维持和管理连接
    • 连接器内部也是一个 连接池,里面维护了各个系统跟这个数据库创建的所有连接
    • Java 系统连接Mysql 的过程
      • 首先完成TCP的三次握手,创建一个网络连接
      • 然后开始权限认证,也就是 你的 用户名 、密码 是否正确
    • 连接成功后,如果没有后续动作,这个连接会处于空闲状态
    • 空闲一定时间后,会自动断开连接,由参数 wait_timeout 控制的,默认值是 8 小时
  • 我们现在已经知道,我们执行SQL,一定要先连接到数据库。数据库的 连接器 会对系统进行权限认证,如果认证成功,就创建了一个数据库连接。
  • 那么,连接之后是怎么执行SQL语句的呢?
  • 一个基本的知识点,网络连接必须要分配给一个线程去处理
    • 由一个 线程 来监听 和 读取 Java系统请求的数据
    • 线程会从网络请求中解析出我们发送的sql语句
  • 线程获取到了我们写好的SQL语句,那交给谁来执行呢
    • 其实在执行之前,还有一步,就是查询缓存
    • 之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中
      • key 是查询的语句
      • value 是查询的结果
    • 如果在缓存中找到 key,那么这个 value 就会被直接返回给客户端
    • 但是,建议不要使用缓存,往往弊大于利
      • 查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空
      • 查询缓存的命中率会非常低
      • 可以将参数 query_cache_type 设置成 DEMAND,关闭缓存
    • MySQL 8.0 版本直接将查询缓存的整块功能删掉了
      • 所以接下来的图,我就不画 查询缓存 这个步骤了
    • 没有了查询缓存这个功能,我们写好的SQL,都是交给查询解析器来分析的
  • 解析器
    • 我们写的SQL 语句,人认识,但是机器是不认识的,所以必须要解析我们的语句
    • 拿一条SQL举例
      • select id,name from user where id = 10

        • 我们的SQL 是由 字符串 和 空格 组成的

          • 有些字符串 是 MySQL 的关键字
          • MySQL 会识别这些关键字
        • 语法解析器 会将 上面的SQL拆解为几部分
          • 要从 user 表里查询数据
          • 查询 id 字段的值,等于 10 的那行数据
          • 对查询的那行数据,提取出 id 、name 两个字段
        • 如果语法不对,解析器会提示我们
          • ERROR 1064 (42000): You have an error in your SQL syntax;
  • 优化器
    • 经过了解析器,MySQL 就知道你要做什么了,在开始执行之前,还要先经过优化器的处理,选择一个最优路径
    • 我们的表可能创建了多个索引,或者多表关联(join)的时候
      • 这时,是有多个路径可以查询到结果的,但是执行效率会不同
      • 查询优化器就是干这个事的,它会选一个效率最高的路径
    • 这个我们后面会仔细分析,这里知道它会选一个最优路径就好。先了解MySQL的整体架构,再深究细节
  • 执行器
    • MySQL 通过分析器知道了你要做什么
    • 通过优化器知道了该怎么做,生成执行计划
    • 于是就进入了执行器阶段,负责这个计划的执行
    • 执行器 主要是 操作存储引擎来返回结果的,我们重点要关注的是存储引擎的执行原理
  • 接下来,我们来研究一下,存储引擎的架构设计,以及如何基于存储引擎来完成一条更新语句的执行。
  • MySQL 有多种存储引擎,InnoDB、MyISAM等,我们就说最常用的InnoDB。接下来的图,我就只画 InnoDB 存储引擎这部分的了,连接、解释器、优化器会去掉,不然画不下了。
  • 我们以一条更新操作来看一下 InnoDB 的运行流程
  • 用这个SQL举例:
    • update users set name = ‘李四’ where id = 10
  • InnoDB 中 重要的内存结构 Buffer Pool
    • Buffer Pool 缓冲池,是 InnoDB 存储引擎的核心组件。这里会缓存大量的数据,查询时会先看 缓冲池 内是否有这条数据,如果有,就可以不用查磁盘了
    • 如果 Buffer Pool 中没有这条数据,就要先从磁盘中加载进来
  • Buffer Pool 中的数据是缓存页,磁盘中的表数据是数据页,内部有其数据结构。我们这里忽略,先看一下整体的运行流程,之后再分析里面的物理结构。
  • undo 日志文件
    • 如果我们执行一个更新语句,在没有提交事务之前,我们都是可以对数据进行回滚的
    • undo 日志文件就是保证我们可以回滚数据的一个组件
    • 举例:
      • 如果我们要把 id = 10 的数据的 name 从 张三 改为 李四

        • 第一步是把数据加载到 Buffer Pool 里
        • 第二步 就要把 id = 10 ,name = 张三 的这条原始数据,写到undo日志文件
      • 如果数据回滚,就会从 undo 日志文件中读取原始数据恢复
  • 备注:InnoDB 是个存储引擎,步骤2 其实也是我们上面说到的 执行器 来把原始数据写到磁盘上的,后面的步骤,但凡有写磁盘、读磁盘的操作,都是执行器执行的。这里为了画图方便,直接连线了
  • 然后 执行器 会更新 Buffer Pool 中的缓存数据
  • 现在,缓存内的数据已经从 张三 更新到 李四 了
    • 那么,现在有一个问题,如果 MySQL 此时宕机了会有问题吗
    • 因为现在还没有提交事务,代表这条语句还没执行完
    • 所以,此时宕机没有关系,事务没提交,重启后内存数据就没了,磁盘数据也没变化
    • 磁盘的数据也是原始数据,所以没关系
  • 我们在内存中修改的数据,终究要刷到磁盘上的。MySQL 不会马上把这条数据刷到磁盘上,会等系统不忙碌时,再刷回去。因为刷磁盘这事,本来实时性要就不高,我们查询的时候也是基于内存的,磁盘是什么数据无所谓,只要保证最终一致就好了。
  • 我们只有提交事务后,才能把内存修改的数据刷到磁盘上
  • 提交事务是一个过程,这个过程中我们需要先写入几份日志文件,只有这几个日志文件都写成功了,事务才算提交成功
  • 所以,这里开始介绍 InnoDB 存储引擎中的另一个组件 Redo log Buffer
    • 内存中的 Redo log Buffer 配合 磁盘上的 redo log 日志文件,可以在 MySQL 意外宕机的情况下,恢复内存数据的。它会记录内存中修改的数据,然后把这些数据刷到磁盘上的 redo log 日志中
  • 之前,我们已经修改了内存数据,在修改完成后,执行器就会向Redo log Buffer 中写入日志,到这一步为止,我们已经执行完了这条SQL语句,就差提交事务
  • 如果我们提交事务,第一步就是把 Redo log Buffer 中的日志刷到磁盘上的 redo log 中
    • 此时,如果 MySQL 宕机,数据是不会丢失的。重启后,会加载磁盘上的 redo log 日志文件,恢复到内存中
  • redo log 日志是 偏物理层面的日志,也叫 重做日志。而 binlog 是归档日志(这个后面说)
    • 为什么说是偏物理层面的日志,就是说不是给人看的,你看了也不知道修改的啥

      • 比如,对哪些数据页上的什么数据做了什么修改
        备注:提交事务,不是一步完成的,是一个过程。后面的步骤 5、6、7都属于提交事务的过程,只要有一步失败,那提交就是不成功的
  • 把 redo log 从内存刷到磁盘的策略有三种
    • 通过参数 innodb_flush_log_at_trx_commit 来配置 ,默认值为 1

      • 值为 0 :提交事务后,不会把 redo log buffer 里的日志刷到磁盘

        • 此时如果 MySQL 宕机,redo log buffer 内数据全部丢失
      • 值为 1 :提交事务后立刻把日志刷到磁盘,只要提交事务成功,那 redo log 一定在磁盘
      • 值为 2 :提交事务后会把 redo log 先刷到 os cache(操作系统缓存) 里 ,然后 os cache 在适当的时机刷入磁盘
        • 在os cache 没刷磁盘期间,如果 MySQL 宕机,这部分数据会丢失
    • 我们平时开发还是要用 innodb_flush_log_at_trx_commit = 1 ,立刻刷磁盘。保证提交事务后,数据绝对不会丢失
  • redo log 是偏物理层面的日志。如果发生数据库操作失误,我们不能根据这个来恢复数据。我们需要用 binlog 来恢复,binlog 是偏逻辑性的日志
  • binlog
    • binlog 也叫 归档日志,是逻辑性的日志

      • 如:对 users 表的 id = 10 的一行数据做了更新操作
    • binlog 不是 InnoDB 存储引擎特有的日志文件,是属于 MySQL Server 自己的日志文件
    • 我们开始提交事务,第一步是把 redo log 日志刷到磁盘, 接下来执行器还要继续写 binlog 日志到磁盘
    • binlog 刷磁盘有两种策略,通过 sync_binlog 参数来配置,默认值 0
      • 值为 0 :先刷到 os cache 缓存,然后不定时刷入磁盘

        • 如果宕机,可能会丢失数据
      • 值为 1 :直接刷到 磁盘文件中 ,是要提交事务成功,数据一定不会丢失
  • 最后,是 事务提交的最后一步
    • 执行器 会把本次更新对应的 binlog 日志的文件名 和 本次更新的 binlog 日志在文件中的位置,都写入 redo log 日志文件中
    • 同时,还会写入一个 commit 标记
    • 只有完成了这一步,才算是 事务提交成功
  • 为什么要在 redo log 中写入 commit 标记呢?
    • 用来保证 redo log 和 bin log 的数据一致性
    • 举例:
      • 如果完成了第5步,刷入了 redo log 后,MySQL 宕机了,那 bin log 就没法写入 commit 标记,那这条数据没有 commit 标记,就是无效的,提交事务失败
      • 如果第6步,刷入了 binlog 后,MySQL 宕机了,一样没有 commit 标记,也是无效的
  • 现在,本条更新语句已经提交了事务,更新完毕了
    • 此时,内存上的数据 已经是 更新过的 name = 李四 ,磁盘上是 name = 张三
    • 此时,MySQL 宕机是无所谓的,数据不会丢失,重启后会从redo log 加载到缓冲池
  • 然后,是最后一个步骤
    • MySQL 有一个后台的 IO 线程,在之后的某个时间,会随机的把内存 Buffer pool 中修改的脏数据刷回磁盘的数据文件中

      • 脏数据:就是内存和磁盘不一致,但是没有什么影响
  • 到现在,我们已经知道了 MySQL 的整体运行流程,和内部的运行原理,MySQL 的全貌我们已经看见了。我们在脑海中要有下面这张图


接下来,我们重点研究每个组件的底层原理,深入的分析里面的细节

MySQL 内核原理分析(一)相关推荐

  1. MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)

    MySQL事务原理分析(ACID特性.隔离级别.锁.MVCC.并发读异常.并发死锁以及如何避免死锁) 一.事务 目的 组成 特征 事务空间语句 二.ACID特性 原子性(A) 隔离性(I) 持久性(d ...

  2. Linux服务器开发【有用知识】—MySQL事务原理分析

    前言 今天的目标是学习MySQL事务原理分析,但是却似乎总是非常不顺利,概念和实操实在多到令人发指,故干脆轻松学完一节课,等到时机到了再重新刷一遍吧! 一.事务是什么? 将数据库从一致性状态转化成另一 ...

  3. mysql主从复制原理分析

    1.主从复制这类NFS存储数据通过inotify+rsync同步到备份的NFS服务器,只不 过Mysql的复制方案是其自带的工具 inotify 是一种文件系统的变化通知机制,如文件增加.删除等事件可 ...

  4. mysql数据库原理分析

    一提到关系型数据库,我禁不住想:有些东西被忽视了.关系型数据库无处不在,而且种类繁多,从小巧实用的 SQLite 到强大的 Teradata .但很少有文章讲解数据库是如何工作的.你可以自己谷歌/百度 ...

  5. mysql第五话 - mysql索引原理分析

    在工作中听到最多的一句话,sql查询太慢怎么办?加个索引吧! 今天来探索一下mysql的索引原理. 1.索引是什么? 可以毫不夸张的说,系统中sql的快慢,是能直接决定你系统的快慢的.但是sql的快慢 ...

  6. MySql应用原理分析系列文章目录

    本系列分析文章 为实际开发中的点点滴滴的总结,从最最简单的SQL 查询 到 综合分析查询 在分析 SQL 时,也会同时分析 mybatis .Hibernate 中的相关操作 每周更新 1-2 篇文章 ...

  7. 数据库之mysql事务原理分析与锁机制 详解

    1.事务 1.2.目的 事务将数据库从一种一致性状态转换为另一种一致性状态: 1.3.组成 事务可由一条非常简单的SQL语句组成,也可以由一组复杂的SQL语句组成: 其中单条语句会默认自动添加事务控制 ...

  8. MYSQL事务原理分析

    目录 事务是什么 ACID特性 原子性(A) 隔离性(I) 持久性(D) 一致性(C) 隔离级别 简介 有些什么 READ UNCOMMITTED(读未提交) READ COMMITTED(读已提交) ...

  9. MySQL优化原理分析及优化方案总结

    前言 今天中午收到我司安全部发了一封邮件:Jackson存在安全漏洞.查了一下,这件事并不算很新鲜了(已经过了5天的样子),本文来聊聊吧. 说起来还蛮戏剧化:阿里云向Jackson官方提交了一个Jac ...

最新文章

  1. 自定义html页面鼠标右键,javascript鼠标右键菜单自定义效果
  2. 新手入门必看:使用Selenium进行自动化测试
  3. 每日程序C语言45-连接两个链表
  4. 微信有电脑客户端吗_微信电脑版有哪些功能呢
  5. SpringCloud Zuul(六)之PRE Filter
  6. 蓝桥杯JAVA省赛2013-----B------2(马虎算式)
  7. Linux下如何编译Android源码~~~
  8. 常用针织实用技术名词
  9. Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]
  10. Unity3D 发布APK安卓环境配置步骤、安装、教程(含Java/Android)(超全流程)
  11. Java VM Options
  12. AD18 设定PCB板子大小
  13. fabao_get.y
  14. 【毕业设计】【周记】STGCN模型的改进和可视化
  15. 数据透视表mysql_MySQL查询和数据透视表
  16. 关于 opengl3.3 - 4.1 ABO 的感触. 传统 VBO往 ABO+VBO的 代码移植
  17. windows xp sp3
  18. ipc通信-共享内存
  19. 2007年简历版本。
  20. 什么是光时域反射仪,OTDR的工作原理是什么

热门文章

  1. 视频教程- 项目管理工具(1) WBS-工作分解结构-研发管理
  2. ShaderGraph笔记——高光裁切
  3. htc 8x android,htc 8x的usb驱动下载
  4. htc+m8+wp+android,WP8.1版HTC One M8官方配置全揭晓
  5. vulnhub FristiLeaks: 1.3
  6. Linux小白详细笔记
  7. 中国成为北极理事会正式观察员国 将享合法权利
  8. C语言常见开发工具的安装和配置
  9. 看盘做短线的10种方法
  10. vue 实现切换主题色(低配版)