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:

  1. insert into user(id, name) values(?, ?);
  2. 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,如上面提到的:

  1. 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的更多相关文章

  1. 预编译语句(Prepared Statements)介绍,以MySQL为例

    背景 本文重点讲述MySQL中的预编译语句并从MySQL的Connector/J源码出发讲述其在Java语言中相关使用. 注意:文中的描述与结论基于MySQL 5.7.16以及Connect/J 5. ...

  2. What is the difference between parameterized queries and prepared statements?

    Both parameterized queries and prepared statements are exactly the same thing. Prepared statement se ...

  3. Raising Error Conditions with MySQL SIGNAL / RESIGNAL Statements

    http://www.mysqltutorial.org/mysql-signal-resignal/ Summary: in this tutorial, you will learn how to ...

  4. iOS开发之SQLite--C语言接口规范(三)——Binding Values To Prepared Statements

    在前面的博客中已经介绍了如何连接SQLite数据库,并且简单的查询和遍历结果集.在前面用到了sqlite3_stmt *stmt,也就是预编译后的SQL语句.在本篇博客中会了解一下sqlite3_st ...

  5. Prepared statements(mysqli & pdo)

    参考: http://php.net/manual/en/mysqli.quickstart.prepared-statements.php http://www.ultramegatech.com/ ...

  6. PHP MySQLi Prepared Statements Tutorial to Prevent SQL Injection

    https://websitebeaver.com/prepared-statements-in-php-mysqli-to-prevent-sql-injection#introduction On ...

  7. MySQL与Oracle 差异比较之七其它

    其它 编号 类别 ORACLE MYSQL 注释 1 内连接的更改 1.select a.*, b.*, c.*, d.*  from a, b, c, d where a.id = b.id   a ...

  8. MYSQL COST optimizer

    http://blog.chinaunix.net/uid-26896862-id-3326400.html https://www.slideshare.net/olavsa/mysql-optim ...

  9. mysql与oracle的语法对比

    数据类型 编号 ORACLE MYSQL 注释 1 NUMBER int / DECIMAL DECIMAL就是NUMBER(10,2)这样的结构INT就是是NUMBER(10),表示整型:MYSQL ...

随机推荐

  1. 【linux基础】Ubuntu16.04桌面突然卡住怎么办?

    使用Ctrl+Alt+F1先进入命令行模式,然后根据问题进行相应的操作. re 1. Ubuntu16.04桌面突然卡住怎么办; 2. Ubuntu下图形界面卡死解决办法; end

  2. [LeetCode] 275. H-Index II H指数 II

    Follow up for H-Index: What if the citations array is sorted in ascending order? Could you optimize ...

  3. ssh登录服务器提示错误no hostkey alg

    ssh登录服务器提示错误no hostkey alg ssh root@192.168.1.100 -vvv 提示失败: no hostkey alg 登录到192.168.1.100服务器 rm - ...

  4. PDF阅读器关闭“使用手型工具阅读文章”功能

    1.问题描述 某些PDF文件打开时,光标显示的手型工具里面有个箭头,一点击鼠标左键,就跳转到下一页了.给阅读带来很多不便. 2.原因 因为这类PDF文档中带有"文章"(articl ...

  5. php imagick生成gif动画的方法

    >php imagick生成gif动画的方法<pre><?php$image=new Imagick();$animation = new Imagick(); //建立一个对 ...

  6. CF-Technocup3 D Optimal Subsequences

    D Optimal Subsequences http://codeforces.com/contest/1227/problem/D2 显然,每次求的k一定是这个序列从大到小排序后前k大的元素. 考 ...

  7. Spring MVC 问题归纳

    记录一些在Spring MVC配置中出现的问题 一.配置tomcat包没有加载 错误: idea调试web项目时出现:java.lang.ClassNotFoundException:org.spri ...

  8. 用海豚框架(DolphinPHP)实现单/多图片上传时,如何获得图片路径

    用框架实现图片上传很简单,就不多说了,然后这个框架的实现机制是这样的,我们选择图片,点击上传,他会将图片保存在uploads下,以当天时间和随机字母作为图片名,然后在返回个数字,这个数字是这个图片的i ...

  9. 不一样的go语言-athens源码概览

    前言   上一篇文章介绍了athens私服的安装以及vgo download protocol的简要介绍.本文着重介绍go proxy sever的实现原理以及athens是如何实现的. go get ...

  10. JavaScript中的原型prototype和__proto__的区别及原型链概念

    问题 初学js的同学,总是搞不清楚js中的原型是什么东西,看着控制台打印出来的一串串__proto__,迷惑不已. 例如我定义一个Person,创建一个实例p,并打印实例. function Pers ...