1. 背景
刚入行时,大部分Java工程师对MySQL停留在一个黑盒的认识,包括我自己。最近一段时间,这几年通过项目实践与不断反思,对MySQL的新认知提升到一个新层次,供大家分享。
下图是初始阶段的认识,就是对数据库建库、建表、建索引,然后执行增删改查操作。
2. 数据库驱动
大家都知道,我们如果要在Java系统中去访问一个MySQL数据库,必须得在系统的依赖中加入一个MySQL驱动,有了这个MySQL驱动,才能跟MySQL数据库建立连接,然后执行各种SQL语句。下面这段maven配置中就引入了一个MySQL驱动。这里的mysql-connector-java就是面向Java语言的MySQL驱动。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
如果我们要访问数据库,必须得跟数据库建立一个网络连接,那么这个连接由谁来建立呢?其实答案就是这个MySQL驱动,他会在底层跟数据库建立网络连接,有网络连接,接着才能去发送请求给数据库服务器!我们看下图。
3. 数据库连接池
一个Java系统难道只会跟数据库建立一个连接吗?这个肯定是不行的,假设我们用Java开发了一个Web系统,是部署在Tomcat中的,那么Tomcat本身肯定
是有多个线程来并发的处理同时接收到的多个请求的,我们看下图
这个时候,如果Tomcat中的多个线程并发处理多个请求的时候,都要去抢夺一个连接去访问数据库的话,那效率肯定是很低的,那么如果Tomcat中的每个线程在每次访问数据库的时候,都基于MySQL驱动去创建一个数据库连接,然后执行SQL语句,再销毁这个数据库连接,这是否可行呢?因为每次建立一个数据库连接都很耗时,好不容易建立好了连接,执行完了SQL语句,你还把数据库连接给销毁了,下一次再重新建立数据库连接,那肯定是效率很低下的!
所以一般我们必须要使用一个数据库连接池,也就是说在一个池子里维持多个数据库连接,让多个线程使用里面的不同的数据库连接去执行SQL语句,然后执行完SQL语句之后,不要销毁这个数据库连接,而是把连接放回池子里,后续还可以继续使用。基于这样的一个数据库连接池的机制,就可以解决多个线程并发的使用多个数据库连接去执行SQL语句的问题,而且还避免了数据库连接使用完之后就销毁的问题,我们看下图的说明。
常见的数据库连接池有DBCP,C3P0,Druid。其实不光是Java系统,如果你是一个Python、Ruby、.NET、PHP的程序员,这个系统与数据库的交互本质都是一样的,都是基于数据库连接池去与数据库进行交互。
4. MySQL数据库的连接池
现在我们已经知道,我们任何一个系统都会有一个数据库连接池去访问数据库,也就是说这个系统会有多个数据库连接,供多线程并发的使用。同时我们可能会有多个系统同时去访问一个数据库,这都是有可能的。
所以当我们把目光转移到MySQL的时候,我们要来思考一个问题,那就是肯定会有很多系统要与MySQL数据库建立很多个连接,那么MySQL也必然要维护与系统之间的多个连接,所以MySQL架构体系中的第一个环节,就是连接池。
我们看下面的图,实际上MySQL中的连接池就是维护了与系统之间的多个数据库连接。除此之外,你的系统每次跟MySQL建立连接的时候,还会根据你传递过来的账号和密码,进行账号密码的验证,库表权限的验证。
6. 数据库线程
现在假设我们的数据库服务器的连接池中的某个连接接收到了网络请求,假设就是一条SQL语句,那么大家先思考一个问题,谁负责从这个连接中去监听网络请求?谁负责从网络连接里把请求数据读取出来?网络连接必须得分配给一个线程去进行处理,由一个线程来监听请求以及读取请求数据,比如从网络连接中读取和解析出来一条我们的系统发送过去的SQL语句。
7. SQL接口
接着我们来思考一下,当MySQL内部的工作线程从一个网络连接中读取出来一个SQL语句之后,此时会如何来执行这个SQL语句呢?
其实SQL是一项伟大的发明,他发明了简单易用的数据读写的语法和模型,哪怕是个产品经理,或者是运营专员,甚至是销售员,即使他不会技术,他也能轻松学会使用SQL语句,因此MySQL的工作线程接收到SQL语句之后,就会转交给SQL接口去执行。
8. 查询解析器
接着下一个问题来了,SQL接口怎么执行SQL语句呢?你直接把SQL语句交给MySQL,他能看懂和理解这些SQL语句吗?比如我们来举一个例子,现在我们有这么一个SQL语句:select id,name,age from users where id=1这个SQL语句,我们用人脑是直接就可以处理一下,只要懂SQL语法的人,立马大家就知道他是什么意思,但是MySQL自己本身也是一个系统,是一个数据库管理系统,他没法直接理解这些SQL语句!所以此时有一个关键的组件要出场了,那就是查询解析器。所谓的SQL解析,就是按照既定的SQL语法,对我们按照SQL语法规则编写的SQL语句进行解析,然后理解这个SQL语句要干什么事情
9. 查询优化器
当我们通过解析器理解了SQL语句要干什么之后,接着会找查询优化器(Optimizer)来选择一个最优的查询路径。所以查询优化器大概就是干这个的,他会针对你编写的几十行、几百行甚至上千行的复杂SQL语句生成查询路径树,然后从里面选择一条最优的查询路径出来。相当于他会告诉你,你应该按照一个什么样的步骤和顺序,去执行哪些操作,然后一步一步的把SQL语句就给完成了。
10. 执行器
执行器会根据我们的优化器生成的一套执行计划,然后不停的调用存储引擎的各种接口去完成SQL语句的执行计划,大致就是不停的更新或者提取一些数据出来。
11. 存储引擎
最后一步,就是把查询优化器选择的最优查询路径,也就是你到底应该按照一个什么样的顺序和步骤去执行这个SQL语句的计划,把这个计划交给底层的存储引擎去真正的执行。这个存储引擎是MySQL的架构设计中很有特色的一个环节。
12. 逻辑架构
现在把上述组件综合起来看得到如下架构与流程图。