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 ...
随机推荐
- Ubuntu下root账户无法使用xshell远程连接解决方法
以前使用xshell连接服务器跑程序都很顺利,但这次整了一个root账户,发现居然连不上.百度一下,发现ubuntu系统本身是拒绝root账户远程连接的. 解决办法:参考点击传送门
- 初进python世界之数据类型
文章来源: https://www.cnblogs.com/seagullunix/articles/7297946.html 基本运算符 常用数据类型: 字符串(Str) 数字(Digit) 列表( ...
- piecewise_construct存在的意义
C++11中大部分的容器对于添加元素除了传统的 insert 或者 pusb_back/push_front 之外都提供一个新的函数叫做 emplace. 比如如果你想要向 std::vector 的 ...
- opengl读取灰度图生成三维地形并添加光照
转自:https://www.cnblogs.com/gucheng/p/10152889.html 准备第三方库 glew.freeglut.glm.opencv 准备一张灰度图 最终效果 代码如下 ...
- vs2010+ARX2012向导添加mfc支持类出现Error in default.htm PopulateDialogIDs():
初步判断为ARX2012默认的编译器平台集是v90,如果你只安装了vs2010,没有安装vs2008sp1或者vs2008sp1的编译器,以及对应的Windows MFC SDK,就可能会出现这样的问 ...
- 十、Spring的@Profile注解
首先我们来看看spring官方文档对这个注解的解释: The @Profile annotation allows you to indicate that a component is eligib ...
- LeetCode 227. 基本计算器 II(Basic Calculator II)
227. 基本计算器 II 227. Basic Calculator II 题目描述 实现一个基本的计算器来计算一个简单的字符串表达式的值. 字符串表达式仅包含非负整数,+,-,*,/ 四种运算符和 ...
- Windows中使用 Python 调用 Matlab 程序
https://ww2.mathworks.cn/help/matlab/matlab_external/system-and-configuration-requirements.html http ...
- 01_Android入门
Android系统文件目录结构 / 代表系统的根目录 /data/app/ 存放着第三方的apk文件 /system/app/ 其中是系统中的应用安装文件 /data/data/packagename ...
- 13 JSP、MVC开发模式、EL表达式和JSPL标签+软件设计架构---学习笔记
1.JSP (1)JSP概念:Java Server Pages 即java服务器端页面可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码用于简化书写!!! (2)原理 ...