1. MySQL驱动 数据库连接池
作为一个 Java工程师,不知道你有没有关注过一个问题,Java程序是如何与MySQL数据库进行交互的?
应该大部分人都知道,我们首先需要配置一个 MySQL驱动,那MySQL驱动到底是个什么东西?
通俗一点解释,MySQL驱动 就是用来跟MySQL服务端进行通信,也就是创建网络连接,然后往服务器发送请求,执行SQL语句 等访问数据库的操作;
一般在项目中也就是这样一个maven依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
对于我们的Java系统,肯定不可能只跟MySQL创建一个连接的,如果只有一个的话,那就得单线程串行执行SQL语句了;
所以需要和MySQL服务端创建多个连接,但是每次创建和销毁一个数据库连接都是非常耗时的操作,那肯定就不能频繁的去创建和销毁了;
这种情况下,就引入了池化思想,也就是数据库连接池;在一个池子中维持多个数据库连接,让不同的线程需要执行SQL语句的时候,先去获取到一个连接,执行完成之后又将这个连接给放回池内;
常见的数据库连接池有:DBCP、C3P0、阿里的 Druid 这些;
这些池化的思想,在我们系统开发中很多地方都会遇到;如 线程池、内存池、HTTP连接池 等等……
可以扩展一下池化思想的一般作用:
- 资源复用:池中对象得到复用,避免了频繁的创建、释放带来的性能开销,减少内存碎片等;
- 更快的响应速度:在要使用到对象时,直接从池中获取即可,不用在要用时才去等待创建;
- 统一的对象管理:可以防止内存泄露,实现线程安全等;
一般来说,我们的系统是部署在Tomcat中的,或者现在的springboot内置的 Tomcat,一个Tomcat服务器中是有多个线程的(Tomcat8默认为200个线程),也就是说这些线程是可以同时接收多个请求,然后并发的处理的;
那把这些过程串联起来就是:
- 部署在 Tomcat 中的Java应用,会通过数据库连接池创建一定数量的数据库连接;
- Tomcat 中也会有多个线程,可以同时接收用户的请求;
- 当有多个用户并发请求时,由Tomcat中的线程来处理这些请求;
在要执行 SQL语句时,从 数据库连接池 中获取到跟 MySQL服务端的数据库连接,然后通过 MySQL驱动来向MySQL服务端发送请求,再由MySQL服务端来执行SQL语句;2. MySQL 架构设计
上面说到通过 MySQL 驱动来发起请求由MySQL服务端执行 SQL 语句,那 MySQL 服务端是怎么执行的呢?
对于 MySQL服务端,其实也会维护一个连接池(连接管理器),用来管理多个客户端跟这个服务端创建的所有连接;
我们平常使用命令行来操作,来跟 MySQL服务端创建一个MySQL连接,一般也就是:
mysql -h$ip -P$port -u$user -p
执行之后,MySQL的连接管理器就会去验证你的账户密码和权限等;如果验证通过,就可以通过命令行来执行MySQL命令了;
这个客户端的连接,MySQL服务端会维护一定的时间长度(默认是8小时),也就是说如果你8小时客户端没有操作,连接管理器会自动将这个连接给断开(不然也是白白浪费资源维护这个连接,也就是要维护执行过程中使用到内存之类的资源);
当MySQL服务端接收到一个 SQL请求之后,也就是说从一个网络连接中接收到网络请求;那这个时候肯定就需要有一个线程来从网络连接中读取和解析请求;
也就是得到一个 SQL语句,转交给SQL接口去执行,完成底层数据的增删改查;
为了执行SQL语句,MySQL的 Server层,设计了如下的 组件:
以这条 SQL 语句为例,解释一下:
select id, name, age from user where id = 1;
解析器:对 SQL 语句做解析,也就是要让MySQL知道你这条 SQL语句,是要做什么;
词法解析:识别出 SQL语句里面的字符串分别是什么,代表什么;比如这里就是:
- select 表示这是一个查询语句;
- user 表示 从user表中进行查询;
- id = 1 表示查询 id为1 这行数据;
- id、name、age 表示要从这行数据中提取这三个字段;
语法分析:根据词法分析的结果,再判断你输入的这个 SQL 是否满足 MySQL的语法;
也就是你在执行 sql 语句的时候,正常报出来的错误这些;
> 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 10' at line 1 > 时间: 0.009s
一般这个报错,都会提示你出现错误的位置,一般就关注
use near...
优化器:当你的SQL语句中有多个索引,或者多个表关联查询时;优化器会决定使用哪个索引,或者决定各个表的连接顺序;也就是说优化器会决定一条 SQL 按照一个什么的步骤和顺序,去执行哪些操作;例如:
select * from t1 join t2 where t1.c=10 and t2.d=20;
既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20;
也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10;
这两种方式的执行结果是一样的,但是可能执行的效率会不同,所以优化器会根据执行成本来选择使用哪个方案;
- 执行器:当通过优化器决定了怎么执行这条 SQL 时,就可以开始执行语句了;
- 在执行之前,判断当前用户对于这个表是否有执行权限;如果有权限,才会打开这个表继续执行后面的操作;
- 具体的执行,是通过执行引擎来实现的;也就是每个表在定义时,就指定了特定的执行引擎,然后 MySQL的Server 去调用具体执行引擎的接口,来执行这条 SQL语句;
- 这里的执行引擎,一般默认就是 InnoDB,当然还有一些 MyIsam、Memory之类的;(这里就有一个面试题,InnoDB 和 MyIsam 的区别是什么,下去背一下就行了);
对于不同引擎,他们的底层实现的存储结构或者存储方式这些都是不一样的;
也就是通过这些组件的配合,以这样一些流程来完成 执行一条 SQL 语句;