MySQL之Prepared Statements
1.概述
prepared statement在MySQL4.1中引进并且增加了一些新的命令:
- COM_STMT_PREPARE
- COM_STMT_EXECUTE
- COM_STMT_CLOSE
- COM_STMT_RESET
- COM_STMT_SEND_LONG_DATA
它还定义了一个更紧凑简洁的结果集格式代替ProtocolText::Resultset来返回结果集。
记住不是所有的语句都是可以预处理的:
1.1 预处理说明
sql预处理首先要求客户端提交需要执行的sql,这时提交的sql不传递真实的参数值,参数以问号的形式传递过去。
eg:
insert into user(id, name) values(?, ?);
select * from user where id = ?;
在mysql服务端完成预编译解析,这里的预编译解析包括解析参数的个数、类型等,然后响应给客户端。接下来客户端第二次交互只需传递参数过去就可以完成一个完整的sql的执行。相比传统的sql执行,预处理需要两次交互,才能完成一次sql执行。
预处理的优势:
(1)预处理sql能一定程度上防止sql注入
(2)sql预编译效率更高
(3)二进制包协议让sql预处理更加高效。
mysql预处理命令参数的封装以及结果集的返回,均采用二进制格式封装数据,体积更小,面向底层,能直接被mysql服务端利用。相比普通sql文本协议传输的数据,二进制协议传输数据更加高效。
2.二进制协议结果集
二进制协议结果集类似ProtocolText::Resultset.它仅包含二进制协议结果集行格式。
ProtocolBinary::Resultset:
Packet:
- lenenc_int column_cout > 0
- column_count * Protocol::ColumnDefinition
- 没有或者很多ProtocolBinary::ResultsetRow
- EOF_Packet
注意:如果CLIENT_DEPRECATE_EOF客户端性能标志被设置,发送OK_Packet,否则发送EOF_Packet。
例如:
3. 二进制协议结果集行
3.1 NULL-Bitmap
二进制协议结果集行由NULL位图组成,该位图包含与结果集+ 2中的列一样多的位以及二进制协议值格式中非NULL的列的值。
ProtocolBinary::ResultsetRow:
3.2 二进制结果集的行(COM_STMT_EXECUTE)
payload:
1 packet header[00]
string[$len] NULL-bitmap,length: (列数 + 7 + 2 )/8
string[$len] values
例子:
3.2.1 NULL-Bitmap
二进制协议将NULL值作为位发送到位图内而不是像ProtocolText :: ResultsetRow那样发送完整字节。 如果发送了许多NULL值,则它比旧方法更有效。
警告:
对于二进制协议结果集行,num-fields和field-pos需要添加2的偏移量。对于COM_STMT_EXECUTE,此偏移量为0。
NULL位图需要足够的空间来为发送的每个列存储可能的NULL位。 其空间计算如下:
NULL-bitmap-bytes = (num-fields + 7 + offset) / 8
导致:
4. 预处理命令说明
4.1 COM_STMT_PREPARE
COM_STMT_PREPARE命令用于客户端往服务端提交一个预处理的sql,如上面提到的:
insert into user(id, name) values(?, ?);
4.2 COM_STMT_EXECUTE
COM_STMT_EXECUTE用于执行预处理sql,正如前面说到的,如果预处理sql需要传递参数,这个命令会发送预处理语句所需要的参数到服务端。如上面的例子,需要传递两个参数id和user的具体值到服务端。
4.3 COM_STMT_CLOSE
COM_STMT_CLOSE用于关闭服务端预处理sql,每一个预处理预处理的sql提交后都保存在mysql服务端的内存当中,每个预处理sql都有一个唯一的id标识,这个命令将发送需要关闭的sql的id,通知服务端可以将所有该预处理sql的资源释放掉(过多的预处理sql保留在服务端会占用较多的内存,因此有必要执行该命令清理无用的预处理sql)。
4.4 COM_STMT_RESET
COM_STMT_RESET命令用于重置COM_STMT_SEND_LONG_DATA命令发送的blob数据。
4.5 COM_STMT_SEND_LONG_DATA
COM_STMT_SEND_LONG_DATA用于往服务端发送字节流数据,通常来说只有在发送blob字段数据才用到该命令。可以多次调用该命令连续传同一个字段的字节的数据,这个命令必须在COM_STMT_EXECUTE命令发送之前执行。
5. 预处理协议结果包说明
mysql预处理结果集采用了二进制协议包进行封装,与普通的查询结果集格式不同。(普通的结果集包采用文本协议包进行封装)。
5.1 普通查询结果集协议包
普通sql查询(相比预处理sql查询)返回的结果集包用文本协议(官方称为Text Protocol)封装。文本协议的结果集包格式根据官网的一个图来说明:

一个结果集包主要包括以下部分(顺序传输):
- one pakcet show field count(第一个packet用于表示返回结果集列数)
- column defines packets(一个列就是一个packet, 格式参考Column Define Pakcet)
- EOF Packet
- row packets(一行数据就是一个packet, 格式参考ResultsetRow Packet)
- EOF Packet
5.2 预处理结果集协议包
预处理结果集包的组成和普通协议包类似,区别只在于row packet(数据以二进制协议格式存放)。
- one packet show field count(第一个packet用于表示返回结果集列数)
- column define packets(一列就是一个packet,格式参考普通协议包的Column Define Packet)
- EOF Packet
- binary row packets(一行数据一个packet,格式参考Binary Row Pakcet)
- EOF Packet
说明:
Binary Row Packet的第一个字节恒为0, 表示paket header, 接下来,由NULL-Bitmap标识那些值为NULL的列,NULL-Bitmap的长度计算方式为(column-count +7 + 2)/8,其中column-count表示列数,而非空的列值以二进制协议格式(协议格式参考Binary Protocol Value)顺序存储在NULL-Bitmap的后面。
提示:
返回相同结果行,预处理协议包所占字节比普通协议包小,在列数越多,列越长的情况下,相差的大小越明显。
5.3 mysql jdbc 预处理
java.sql.preparestatement可以执行预处理sql,mysql jdbc实现了该接口,并且将预处理分为客户端和服务端预处理
5.3.1 jdbc客户端预处理
mysql jdbc默认情况下采用的就是客户端预处理。客户端预处理的意思是,所有预处理参数都将被缓存在mysql jdbc层,而不是缓存在mysql server。在PrepareStatement执行的时候,在jdbc端完成sql语句的拼接(主要是使用缓存的参数对sql中问号?进行替换, 最终发送到mysql的就是完整的sql语句)。客户端预处理走得是普通的查询协议,而不是真正的mysql预处理协议。
6 Mycat预处理实现机制
Mycat也实现了mysql的预处理协议,可以接收预处理命令的处理。当使用预处理查询,也可以返回正确的二进制结果集包。Mycat预处理的实现是一种取巧的设计,查询走到后端mysql实际上不是发送了预处理命令,而是普通的COM_QUERY命令,后端mysql返回给Mycat的结果集包也是文本协议包,只是在Mycat将结果集包发送往客户端的中间过程,将普通的文本协议结果集包包装成为二进制协议结果集包,然后再返回给客户端。
Mycat预处理的处理流程:
(1)Mycat接收到客户端发送的COM_STMT_PREPARE命令后,解析协议包的内容得到预处理sql语句,eg:insert into user(id, name)value(?, ?),将这些预处理语句缓存在Mycat里面;
(2)当Mycat再次接收到客户端发送的COM_STMT_EXECUTE命令,就把相应的问号替换为实际传递过来的参数值,这时候已经得到了完整的sql语句。
(3)接下来,直接把这个语句丢给Mycat sql查询处理器去执行,中间会经过sql解析模块,路由解析模块以及最后的执行。
(4)最后,当收到后端mysql传递给Mycat的数据准备发往客户端的时候,做一个协议转换,将普通文本结构集协议包转换为二进制结果集协议包并发往客户端。
MySQL之Prepared Statements的更多相关文章
- 预编译语句(Prepared Statements)介绍,以MySQL为例
背景 本文重点讲述MySQL中的预编译语句并从MySQL的Connector/J源码出发讲述其在Java语言中相关使用. 注意:文中的描述与结论基于MySQL 5.7.16以及Connect/J 5. ...
- What is the difference between parameterized queries and prepared statements?
Both parameterized queries and prepared statements are exactly the same thing. Prepared statement se ...
- Raising Error Conditions with MySQL SIGNAL / RESIGNAL Statements
http://www.mysqltutorial.org/mysql-signal-resignal/ Summary: in this tutorial, you will learn how to ...
- iOS开发之SQLite--C语言接口规范(三)——Binding Values To Prepared Statements
在前面的博客中已经介绍了如何连接SQLite数据库,并且简单的查询和遍历结果集.在前面用到了sqlite3_stmt *stmt,也就是预编译后的SQL语句.在本篇博客中会了解一下sqlite3_st ...
- Prepared statements(mysqli & pdo)
参考: http://php.net/manual/en/mysqli.quickstart.prepared-statements.php http://www.ultramegatech.com/ ...
- PHP MySQLi Prepared Statements Tutorial to Prevent SQL Injection
https://websitebeaver.com/prepared-statements-in-php-mysqli-to-prevent-sql-injection#introduction On ...
- MySQL与Oracle 差异比较之七其它
其它 编号 类别 ORACLE MYSQL 注释 1 内连接的更改 1.select a.*, b.*, c.*, d.* from a, b, c, d where a.id = b.id a ...
- MYSQL COST optimizer
http://blog.chinaunix.net/uid-26896862-id-3326400.html https://www.slideshare.net/olavsa/mysql-optim ...
- mysql与oracle的语法对比
数据类型 编号 ORACLE MYSQL 注释 1 NUMBER int / DECIMAL DECIMAL就是NUMBER(10,2)这样的结构INT就是是NUMBER(10),表示整型:MYSQL ...
随机推荐
- c++ stl bind函数介绍
/* stl::bind 使用 */ #include <iostream> #include <string> #include <functional> /* ...
- 查看appPackage和appActivity的多种方法
一.通过adb shell 查看 adb shell dumpsys activity | grep 包名 列如: C:\Users\admin>adb shell root@shamu:/ # ...
- preHandle、postHandle与afterCompletion
preHandle 调用时间:Controller方法处理之前 执行顺序:链式Intercepter情况下,Intercepter按照声明的顺序一个接一个执行 若返回false,则中断执行,注意:不会 ...
- [LeetCode] 502. IPO 上市
Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Cap ...
- Kubernetes 基于 RBAC 的授权(十六)
目录 一.RBAC介绍 1.1.角色和集群角色 1.2.RoleBinding 和 ClusterRoleBinding 1.3.资源 1.4.主体 二.命令行工具 2.1.kubectl creat ...
- 【神经网络与深度学习】【计算机视觉】Fast R-CNN
转自:https://zhuanlan.zhihu.com/p/24780395?refer=xiaoleimlnote 首先声明:本文很多内容来自两个博客: RCNN, Fast-RCNN, Fas ...
- vue-cli3 element 分页组件el-pagination的基本使用
<!--分页组件--> <el-pagination :total="total" :current-page="currentPage" : ...
- SQL查询优化思维即SQL子查询
一. 什么叫子查询 定义及分类 子查询又称内部查询,而包含子查询的语句称之外部查询(又称主查询).所有的子查询可以分为两类,即相关子查询和非相关子查询. 非相关子查询是独立于外部查询的子查询,子查询总 ...
- Module 'mysql' already loaded in Unknown on line 0解决方法
Module 'mysql' already loaded in Unknown on line 0解决方法 直接进入php.ini 把;extension=mysql.so注释掉就好了
- leetocode 207 课程表
解题思路: 本题可约化为:课程安排图是否是 有向无环图(DAG).即课程间规定了前置条件,但不能构成任何环路,否则课程前置条件将不成立. 思路是通过 拓扑排序 判断此课程安排图是否是 有向无环图(DA ...