前言
这次新开了一个集体的 mysql 专栏,专门用于总结 mysql 的一些细节以及相干的案例总结,同时也包含了一些 mysql 的底层实现,在后续的篇章则是依据《mysql 技术底细 innodb 存储引擎》(第二版)来深刻理解 mysql 中用的最多的存储引擎的外部细节。
什么是数据库驱动?
mysql 的驱动置信每一个做开发的人员都很相熟,在通常的状况下咱们只须要引入一个 mysql 的依赖同时应用 jdbc 的模板代码就能实现一次 mysql 的连贯。
一次网络连接必须要让线程来进行解决
毫无疑问,一次网络连接不论是在 tomcat 还是在 mysql 的外部都是通过一个独自的线程进行治理的,当然 tomcat 的线程和 mysql 的线程没有任何的关系。
咱们通常状况下都是间接应用 tomcat 的 servlet Api 进行开发,同时 Servlet 的每一次拜访都是一个独自的线程,意味着每个用户的拜访都是互相隔离的,然而如果咱们数据库驱动连贯是单线程的并且只能有一个用户连贯,当之前的线程还在连贯解决数据,前面的线程进行连贯那么之前的解决数据的数据库连贯就会断开,这样必定是不行的,同时如果线程用完之后就被抛弃,这样也会造成资源的节约甚至有可能呈现闲暇线程明明有很多然而零碎因为某种状况无奈回收等问题,最终导致线程期待数据库的连贯申请等问题,基于这些问题数据库有了 连接池 的概念。
数据库连接池
连接池的作用就是维持数据库当中多个数据库连贯,当有线程拜访的时候就会从连接池当中调配一个连贯给对应的线程。另外 mysql 架构当中的第一个重要体系概念就是连接池,值得注意的是 连接池并不是单方面的的,而是在连贯方和 mysql 数据库驱动方都会存在一个数据库的连接池。
依据下面的介绍,咱们绘制出上面的一张图,能够看到其实在 tomcat 的外部以及 mysql 服务器的外部都有一个对应的连接池进行对应,有了数据库连接池之后,每一个用户解决完数据库的申请会把线程归还给线程池,这样不仅进步了线程的复用率又保障了每一个用户的数据库连贯和操作是独立的。
疑难:1. mysql 数据库连接池最多能够开启多少个连贯?2. 如何管制 mysql 的连接数?
解答:1、查看最大连接数
show variables like '%max_connections%';
然而这里有一个参数叫做 'max_user_connections' 的参数,这个参数和 'max_connections' 有什么关系呢?
max_connections 是指整个 mysql 服务器的最大连接数;max_user_connections 是指每个 MySQL 用户的最大连接数
2、批改最大连接数
set GLOBAL max_connections = 200;
mysql 的根本构造
上面咱们来看下 mysql 的根本构造是什么,从外层来看,整个申请的解决仿佛都是在 mysql 服务器外面进行解决,然而实际上 mysql 设计必定不会这样简略,在 mysql 的外部,他会被拆分为上面这几个组件:
sql 解析器:解析用户发来的 sql 语言,负责剖析语法,对于 sql 语句进行拆解等相干操作。
查问优化器:查问优化器负责解析之后的 sql 语法进行逻辑的优化,保障 sql 能够依照最短门路来执行
存储引擎:存储引擎是用于真正执行 sql 的组件,存储引擎依照 sql 语句进行内存和硬盘上的数据更新操作。同时应用对外的接口进行操作。
执行器:执行器就是负责真正调用存储引擎上接口的组件。
上面咱们依照下面的程序通过图画来形容 mysql 外部是如何运作的:
sql 解析器:
当咱们通过 tomcat 发送一条申请的时候,数据库连贯会干啥,他会依据 tomcat 发来的查问语句,通过一个叫做 sql 解析器 的货色进行解析,其实数据库服务器自身也不晓得这条语句干啥用的,所以 sql 解释器负责管理这个货色,在通过 sql 接口承受到申请之后,会传递个 sql 解析器去进行解析动作。
select id,name,age from users where id=1
个查问解析器 (Parser) 就是负责对 SQL 语句进行解析的,比方对下面那个 SQL 语句进行一下拆解,拆解成以下几个局部: 咱们当初要从“users”表里查问数据
查问“id”字段的值等于 1 的那行数据
对查出来的那行数据要提取外面的“id,name,age”三个字段
通过下面的案例咱们能够晓得了,Sql 解析其实就是合成 sql 语法,通过 sql 语法分析出具体要做什么事件。
查问优化器
既然晓得了如何解析,上面就应该理解如何进行查问优化了。查问优化器顾名思义就是对于查问的门路进行优化和抉择,比方上面的 sql 语句有两种抉择(当然数据库实在执行必定不是这样的,然而咱们能够含糊的了解)
- 查问 id=? 的记录,并且提取对应的字段
- 找到须要的三个字段的所有数据,并且从中抉择 id=? 的数据
查问优化器就是用来优化查问逻辑的,会用 最短的查问门路对于查问进行优化。
当然这种优化是无限的,更多状况下还是要看 sql 语句的查问逻辑是否简单以及 sql 的品质是否足够好。
存储引擎
既然查问优化器还不是执行查问的中央,那么咱们接下来再来看下查问优化器解决完之后如何解决。
咱们都晓得数据库无非是由一种非凡的数据结构结构的文件罢了,只是对外提供特定的接口以及须要依照 mysql 的语法能力对数据进行 crud,既然是操作数据,那必定逃不过硬盘和内存,既然存储引擎是间接和这个数据结构打交道的,那么通过查问优化器优化过的的查问语句必定是要交给存储引擎的,既然执行语句的操作是交给存储引擎的,换句话说就是 决定如何解决 sql 的最终执行权在存储引擎手上。
执行器
存储引擎能够执行 sql 语句,然而谁来操作存储引擎的接口呢?实际上调用存储引擎接口的是执行器 ,执行器会依照存储引擎的接口依照肯定的逻辑对 sql 进行执行。那么要如何调用接口呢?执行器会依据以后的存储引擎配套一份 执行打算,而后调用存储引擎实现 sql 的语句对于数据进行增删改查。
依据下面的介绍,咱们能够发现实际上 mysql 最外围的局部是 存储引擎,它是真正在做事的一个组件。所以上面将会介绍 innodb 存储引擎的构造:
innodb 存储引擎和构造
这里跳过 innodb 的介绍,咱们间接来理解外部的具体构造:
缓冲池
innodb 应用缓冲池来缓解磁盘操作的压力,尽量让数据的操作在内存中进行,同时应用不定时脏数据刷盘的操作将内存的数据同步到磁盘,和少数的缓存作用了解一样,在进行查问的时候如果发现命中了缓冲池则会查缓存的数据,否则查磁盘的数据。在查缓存的时候为了避免其余的线程把缓冲池的数据变脏,会对数据进行 加锁 的操作。
undo 日志
undo 日志作用和咱们平时的 ctrl+ z 的原理是一样的,在 更新数据 之前 innodb 须要 先把批改的前的数值放到 undo 日志外面,而后在执行后续的操作,这个 undo 日志也实现事务回滚的组件,理解 mysql 咱们都晓得数据要么在事务外面要么在事务执行之前的 undo 日志,一旦事务操作失败或者手动调用回滚 rollback,此时 mysql 就须要依据 undo 日志的内容把数据进行回滚。
redo 缓冲池和 redo 日志文件
redo 日志翻译过去就是重做日志,他的构造相似缓冲池和硬盘的链接形式,所以从了解上来看须要看作两局部缓冲池和日志文件,整个 redo 的作用就是 记录哪一行的数据进行了批改 并且在 事务提交 将缓存刷新到日志文件进行同步。(说白了还是磁盘 io)
理解了根本 redo 作用之后咱们来思考一下如果 mysql 服务操作数据的时候产生了数据失落的状况,会呈现什么状况?
为了解决这个问题,innodb 在筹备执行事务之前会当时操作一遍 redo log buffer 的缓冲区,这个缓冲区用来寄存哪一行文件的那个字段被批改了,记录数据所在的地位以及改变的数据内容等。
事务没有提交,宕机了如何解决?
数据库当中每次执行一条 sql 都是一个事务的提交。如果数据库解体则会呈现 redo 日志失落的状况,时候 mysql 如何解决?
这个问题很简略,事务都没有提交,阐明数据压根没有批改,而且此时尽管缓冲池的数据变了,然而磁盘数据行的内容没有变,所以 redo 缓冲池的数据失落了也没有影响,当宕机重启复原之后将会通过 undo 日志把内容进行还原。
提交事务之后将 redo 日志写入磁盘
事务提交之后,此时 redo 会应用肯定的策略把 redo_log_buffer 的数据刷新到磁盘文件中,能够通过一个配置:innodb_flush_log_at_trx_commit更改策略
当这个值为 0 的时候 不会把 redo_log_buffer 的内容刷新到磁盘,此时如果 mysql 宕机,内存的文件就全副失落了:
如果把这个值设置为 1:就会在事务提交胜利之后把 redo 缓存数据刷新到日志文件当中,并且文件当中也会存在一条你批改了 xxx 行那个字段的记录。
如果此时缓冲池的内容更新了,redo 日志的内容也更新了,redo 文件外面的内容也记录了记录的批改内容,此时 mysql 忽然宕机了会导致磁盘文件的磁盘数据的不统一么?
必定不会的,如果此时一旦宕机,缓冲池就会去 redo 日志复原之前的批改操作如果 innodb_flush_log_at_trx_commit 设置为 2,会是什么状况?
此时提交事务的时候会把 redo 日志写到 os cache 外面,而不是写入磁盘,可能会是 1 秒之后才会把 os cache 的数据写入到磁盘文件。
然而此时须要留神这个日志文件是在 cache 外面的,所以意味着一旦宕机 os cache 的日志内容也没了。
三种 redo 日志刷盘策略到底抉择哪一种?
提交事务的时候,咱们对 redo 日志的刷盘策略应该抉择哪一种? 每一种刷 盘策略的优缺点别离是什么? 为什么?
如果对于数据特殊要求个别状况下选 1 就能够了,如果选 0,mysql 一旦宕机就生效了,如果选 2,同样尽管数据是写入到零碎缓存的当中。然而还是在内存外面,只有断电宕机,数据同样会失落。
Binlog 日志
咱们先看下 binlog 日志在整个 mysql 执行过程中的过程步骤:
Bin log 日志是什么
在具体介绍之前,咱们还是从 redo log 开始,redo log 能够看作是保障事务一致性和数据正确的外围组件,在事务提交之前会将提交记录写入到 redo log 避免 mysql 宕机失落数据的问题。
然而这一切都是基于存储引擎 innodb 解决的,其实在存储引擎的前一步 执行器 也有一个日志,那就是 bin log 日志。
论断:Binlog 是属于 mysql server 中执行器实现事务的重要内容。
binlog 的工作流程
其实就是 innodb 存储引擎在 redo log 筹备好数据并且刷新到磁盘之后,执行器会把数据写入到一个 binlog 的日志文件进行存储。
执行器是十分外围的组件,须要配合存储引擎进行一个 sql 在磁盘和内存的全副操作。
binlog 的刷盘策略
要害参数:sync_binlog 管制刷盘策略,默认值为 0 。bin 写入磁盘之后,不是间接进入文件,而是和 redo_log 的参数设置 2 一样(innodb_flush_log_at_trx_commit = 2)写入到 os 缓冲池当中,当然会呈现宕机的时候失落缓冲池数据的问题。
如上图所示的 5,6 开始,就是你提交事务的阶段了。此时如果产生宕机,会和之前的 redo_log 一样失落内存的文件。
如果把 sync_binlog 参数设置为 1,则会呈现在提交事务的时候,强制把缓冲的数据刷新到 binlog 磁盘外面。
写入 commit 标记
为什么有了 redo_log 还须要 binlog 呢?
整个事务须要在 binlog 实现了文件和写入到地位记录之后并且在 redolog 外面写入 commit 标记之后才进行解决。所以有了 binlog 之后,能保障整个事务的最终一致性和完整性。
redolog 外面写入 commit 标记有什么意义?
实质上是为了保障 redolog 和 binlog 一致性用的。
相干面试题
【腾讯二面】5s 内建设多少个 mysql 连贯?:https://blog.51cto.com/u_15127515/2684815
总结
咱们从数据库的驱动介绍开始,介绍了整个 mysql 的工作流程,同时介绍了 innodb 存储引擎的工作流程,最初咱们介绍了执行器的一个要害日志 binlog 日志的作用以及理论的运行成果。
写在最初
下一节将会依据一些生产的案例来看看如何进行 mysql 的优化。