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

  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. Ubuntu / CentOS 安装 Anaconda 并创建虚拟环境

    Anaconda可以很好地帮我们管理Python的虚拟环境,Windows上操作极其方便,现在讲一下 Ubuntu 和 CentOS 上的使用方法 ubuntu 安装Anaconda版本 安装方法一: ...

  2. matlab学习笔记8 基本绘图命令-初级二维绘图/交互式绘图

    一起来学matlab-matlab学习笔记8 基本绘图命令_5 初级二维绘图/交互式绘图 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合应用&g ...

  3. kubernetes核心原理之API Server原理分析

    kubernetes API Server的核心功能是提供了Kubernetes各类资源对象(Pod,RC,Service等)的增删改查及Watch等HTTP Rest接口,成为集群内各个功能模块之间 ...

  4. 进入docker 内部

    $ sudo docker ps $ sudo docker exec -it 775c7c9ee1e1 /bin/bash

  5. LeetCode 78. 子集(Subsets) 34

    78. 子集 78. Subsets 题目描述 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明: 解集不能包含重复的子集. 每日一算法2019/6/6Day 34L ...

  6. Markdown 测试用例

    标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 字体 *斜体文本* ...

  7. configparser 文件加字典操作

    import configparser conf=configparser.ConfigParser() #創建一個對象 # f=open('db.ini','w') conf['DEFAULT'] ...

  8. 解决SQL server 18740、18456登录失败问题

    第一步:使用window管理员用户登录SQL server 第二步:如下图步骤(开始配置sa默认用户) 第三步:选择角色类型 第四步:选择和配置用户映射的数据库 第五步:授予允许连接,并开启登录权限 ...

  9. quartz2.3.0(二)触发器Trigger花式Scheduler调度job

    任务类 package org.quartz.examples.example2; import java.util.Date; import org.slf4j.Logger; import org ...

  10. k8s部署traefik

    基础知识 同nginx相比,traefik能够自动感知后端容器变化,从而实现自动服务发现.  traefik部署在k8s上分为daemonset和deployment两种方式各有优缺点: daemon ...