download:Go开发者的涨薪通道:自主开发 PaaS 平台外围性能
一条SQL语句从头到尾
1.一段SQL是怎么诞生的?
SQL语句都诞生在客户端。生成一条SQL次要有两种形式,一种是开发人员自己手工编写,另一种是相干的ORM框架主动生成。一般MySQL运行过程中收到的SQL大多是ORM框架生成的,比如Java中的MyBatis和Hibernate框架。
同时,SQL生成的时机一般与用户的请求无关。当用户在零碎中执行操作时,通常会生成一条SQL。例如,咱们在阅读器上输出以下URL:
此时会先请求掘金的服务器,而后掘金外部实现中的ORM框架会根据请求的参数生成一条SQL,类似于上面的伪SQL:
select * from金爵_article其中userid = 862486453028888
这个SQL大抵意义是:根据用户请求的“作者ID”,查问掘金数据库文章表中该作者的所有文章信息。
从下面的案例可能显著感觉到,在用户阅读器上看到的数据一般来自于数据库,而数据库执行的SQL来自于用户的操作。这两者是互补的,包含任何写操作(增加、删除、更改),本质上也会转换成SQL的片段。让我举一个简略的例子:
请求URL(请求URL)
https://www.xxx.com/user/regi...
请求参数(请求参数)
{
User_name:“竹子爱熊猫”,
user _ pwd:“123456”,
用户_性别:“男”,
用户_电话:“18888888888”,
......
}
这里对用户明码的处理不够谨严,不做加密也不必在意~
复制代码
例如,在上述用户注册的情况下,当用户点击网页上的“注册”按钮时,将向目标网站的服务器发送post请求,而后将根据请求参数生成一条SQL,如下所示:
insert into table_user(用户名,用户明码,用户性别,用户电话,....)
价值观(“竹子爱熊猫”、“123456”、“男”、“188888888”,...);
复制代码
也就是说,一条SQL的诞生源于一个用户的请求。在开发程序时,SQL的一般逻辑会由业务层的代码决定,而具体的SQL语句会根据用户的请求参数和事先定制的“SQL骨架”做出。当然,在Java程序或者其余语言编写的程序中,只能生成SQL,SQL的真正执行需要数据库来实现。
第二,SQL在执行之前将经历的一个过程
通过上一步,一个完整的SQL就诞生了。为了让SQL失常执行,咱们将首先获得一个数据库连接对象。上一篇对于MySQL架构的文章,已经讲过MySQL的连接层有一个叫“连接池”的小工具的保护,不过相信大家都接触过这个货色,比如C3P0,德鲁伊,DBCP等等在Java里。
至此,咱们可能在这里思考一个问题。数据库保护自己的连接池,为什么咱们还需要在MySQL客户端保护一个数据库连接池?接下来咱们聊聊。
2.1、数据库连接池的必要性
家喻户晓,当你要用Java创建数据库连接时,首先会读取配置文件中的连接地址、账号密码等信息,而后发动网络请求,根据配置的地址信息获取数据库连接对象。在这个过程中,因为涉及到网络请求,此时必然会经历TCP三次握手的过程。同时,在获得连接对象并实现SQL操作后,将开释数据库连接。这时分就需要经历TCP挥动四次的过程。
从下面的描述中可能清晰地感知到,Java中创建和敞开数据库连接的过程实际上耗费了大量的成本,而且程序上线后,还需要频繁的数据库操作。所以,如果每次操作数据库都获得一个新的连接对象,那么整个Java程序至多有四分之一的工夫要做TCP三次握手/四次wave的工作,对整个零碎的后果不堪设想。....
正是因为以上原因,才出现了家喻户晓的“数据库连接池”。“数据库连接池”的思维和“线程池”是一样的,会把数据库连接到这个宝贵的资源上,用池技术来保护这个资源。也意味着当前需要进行数据库操作时,不需要自己建立连接,而是可能间接从“数据库连接池”中获取,用完之后放回连接池,达到重用的成果。
当然,连接池中保护的连接对象不会一直存在。当长时间不执行SQL操作时,连接池也会销毁这些连接对象,必要时再从新创建。然而什么时候创建,什么时候销毁,限度连接数等等,都是交给连接池来实现,不需要开发者自己关注。
好了~,回到后面抛出的问题,为什么需要用MySQL连接池在客户端保护一个连接池?
这个问题相信每个人心里都有一些答案。原因很简略。两者都使用池化技术来重用资源,俭约开销,提高性能,但针对的方向不同。
MySQL的连接池次要是为了重用线程,因为每一个数据库连接都会被MySQL中的一个线程保护,而每一次连接对象调配给一个客户端,都需要经历创建线程、调配堆栈空间这样沉重的工作...这个过程需要工夫,资源开销也不小,所以MySQL通过使用池化技术来解决这些问题。
客户端的连接池次要是为了重用数据库连接,因为每一个SQL操作都需要经历TCP三次握手/四波的过程,同样耗时耗力,占用资源。所以也采纳了池化技术来解决这个问题。
其实也可能这样理解,MySQL连接池保护的是工作线程,而客户端连接池保护的是网络连接。
2.2.在执行SQL之前会发生什么
回到本文的主题,当生成完整的SQL时,咱们将首先尝试在连接池中获取一个连接对象。接下来会发生什么?
在尝试从连接池中获取连接时,如果此时连接池中有空闲的连接,可能间接获取重用。但如果不是,你首先要判断以后池中的连接数是否达到了最大数量。如果连接数已满,以后线程需要等待其余线程开释连接对象。如果没有,您可能间接创建一个新的数据库连接来使用。
假设此时连接池中没有空闲的连接,需要再次创建新的连接,那么首先会发动一个网络请求来建立连接。
①首先,将考据客户端的用户名和明码是否正确:
如果用户名不存在或明码谬误,将抛出错误代码1045和谬误消息。
如果用户名和明码通过考据,请转到步骤②。
②必定MySQL连接池中是否有空闲线程:
存在:间接从连接池中调配一个空闲线程来保护以后客户端的连接。
否:创建一个新的工作线程(映射内核线程,调配堆栈空间...).
worker线程会先查问MySQL自己的用户权限表,获取以后登录用户的权限信息,并进行授权。
至此,执行SQL前的筹备工作已经实现,执行SQL的通道已经打开。下一步是筹备执行SQL语句,工作线程将等待客户端传送SQL。
三。SQL语句是如何在数据库中执行的?
通过连接层的一系列工作,客户端会通过连接发送要执行的SQL语句,而后由MySQL服务层进行处理。然而根据用户的操作不同,MySQL执行SQL语句时会有一些区别,SQL语句指的是读操作和写操作。这两条SQL语句的执行过程是不同的。咱们先来看看select语句的执行过程。
3.1.一个查问SQL的执行过程
在分析查问SQL的执行过程之前,咱们先模拟一个案例进行后续分析:
- SQL语句
Select id fromZZ _ user
其中user sex =男性,user_name =竹四号";
-表格数据
- +
|用户标识|用户名|用户性别|用户电话|
- +
- +
| 1 |竹① |男| 1888888888 |
| 2 |竹② |男| 1358888888 |
| 3 |竹③ |男| 1568888888 |
| 4 |熊猫① |女| 1348888888 |
| 5 |熊猫② |女| 1858888888 |
| 6 |竹④ |男| 17777777 |
| 7 |熊猫③ |女| 166666666 |
- +
- +