一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情
前言
今天突然想到MySQL是如何处理我发送的请求呢?这篇文章讲一下我对客户端发送一个SQL请求到MySQL的执行流程,本文我站在一个Java开发的角度去分析这个问题。
1.建立连接
我们知道,对于MySQL来说我们的Java程序就是client客户端,而MySQL就是server服务端,我们发送一个SQL,MySQL接收请求,如何处理,中间必然需要建立连接,有连接必然就会有连接的关闭和开启,那会不会有连接池呢?
抱着好奇的心里我去翻看了很多资料,果然,MySQL是有连接池来管理连接的,并且是TCP连接,对我们java代码层面来说,如果写过jdbc的同学肯定知道,第一步就是新建connection数据库连接,根据我们的账号名密码以及登录ip去做权限,如果账号密码错误一个 access denied for user的错误,如果是登录ip为开放,也就是当前账号未开启远程登录的权限,就会抛出一个connect to MySQL on ’192.168.x.x’的错误,如果一切正常就连接成功,然后打开连接,在执行后续操作,最后关闭连接。
2.处理连接
处理连接简单来说就是执行我们的SQL,稍微详细点说就是解析和执行我们的SQL,假设我们发送的是一个select语句,会先去查询缓存,key就是select语句,如果有就直接返回结果,否则去解析SQL的词法、语法,最终生成一颗语法书提供给优化器做优化处理。
什么是词法?什么是语法?假设有如下SQL:
select id,className,address from class c where c.id < 1000 and c.className like '%掘金%';
词法:就是会将我们的关键字解析出来,比如select,from,id,className,c,like等······,词法解析会将我们select查询的字段映射出来,比如上面有查询id,实际上最终的SQL是:
select class.id,class.className,class.address from class where class.id < 1000 and class.className like '%掘金%';
这里我们可能会想,为什么需要多此一举呢?非要加上表明吗?我们来看这种情况,有如下SQL
select id from class inner join student on student.class_id = id where name = "掘金小课堂";
毫无疑问会报错,这也是刚开始写SQL时经常发送的错误,如下图
ambiguous翻译过来就是模糊的,很显然在student、class两个表里都有id这个字段,MySQL在词法解析的时候不清楚,你是要student.id还是class.id。
语法:这个写过SQL的都清楚,大部分情况下SQL报错都是你的SQL写的有问题,不符合MySQL的语法规定。 假设有如下SQL,我们将join后面的on关键字去掉,再来执行,会抛出
select id from class inner join student student.class_id = id where name = "掘金小课堂";
错误:right syntax to use near '.class_id = id' at line 1,意思就是在class.id附近有语法错误。
最后如果词法和语法都没错的话,SQL解析器会生成一颗语法书,如下图
最终MySQL的优化器会根据语法书去优化SQL,比如将子查询变成join连接查询以及决定是否使用索引,使用哪个索引最后生成一个执行计划,执行的时候回去检查当前账号是否有执行该操作的权限,比如在公司组长给开发使用的账户一般都是readOnly只读账户,当我们执行select语句时没有问题,但是执行update/delete/insert时,就会抛出当前账号是只读权限,最终去执行SQL然后将结果缓存到query_cache中,供下次缓存命中(ps:MySQL8.0将缓存移除)。
总结
MySQL的执行流程:SQL语句 -> 查询缓存 -> SQL分析器 -> SQL优化器 -> SQL执行器