PHP PDO深入探索

引子

学而时习之.用了这么多年的PDO,就知道预处理和参数绑定,但是对于其具体实现并没有进行深入了解.今天好奇心大发了,习MySQL PDO吧.

官释

很多更成熟的数据库都支持预处理语句的概念。什么是预处理语句?可以把它看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。预处理语句可以带来两大好处:

  • 查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析/编译/优化周期。简言之,预处理语句占用更少的资源,因而运行得更快。
  • 提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理。如果应用程序只使用预处理语句,可以确保不会发生SQL 注入。(然而,如果查询的其他部分是由未转义的输入来构建的,则仍存在 SQL 注入的风险)。 预处理语句如此有用,以至于它们唯一的特性是在驱动程序不支持的时PDO 将模拟处理。这样可以确保不管数据库是否具有这样的功能,都可以确保应用程序可以用相同的数据访问模式。

PS:存储过程会稍有特殊,具体请看:http://php.net/manual/zh/pdo.prepared-statements.php

上下而求索

其实细心的会发现官释有句很特别的话[以至于它们唯一的特性是在驱动程序不支持的时PDO将模拟处理].
驱动程序,模拟处理?
直接上代码吧.

1.模拟处理


<?php
$pdo = new PDO("mysql:host=127.0.0.1;dbname=words;charset=utf8","root","password");
$st = $pdo->prepare("SELECT `words`.* FROM `words` WHERE word = ? ORDER BY `id` DESC LIMIT 10 OFFSET 0");
$word = 'charm';
$st->bindParam(1,$word);
$st->execute();
$data = $st->fetchAll();

运行后使用

wireshark

进行抓包查看.一次完成的PHP运行MySQL PDO查询的TCP包就呈现在眼前:

简单的回顾一下TCP握手协议

TCP三路握手

TCP关闭确认

回归正题,MySQL的查询体现:

变化就是替换并添加上了单引号(转义,同mysql_real_escape_string).其他没有什么变化.

2.驱动处理
代码正如:


<?php
$pdo = new PDO("mysql:host=127.0.0.1;dbname=words;charset=utf8","root","password");
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);//这行是关键
$st = $pdo->prepare("SELECT `words`.* FROM `words` WHERE word = ? ORDER BY `id` DESC LIMIT 10 OFFSET 0");
$word = 'charm';
$st->bindParam(1,$word);
$st->execute();
$data = $st->fetchAll();

哇噢,这次跟上次大不一样.来看看具体做了什么.
先是进行了SQL预处理.

根据MySQL协议返回的预处理完成信息.

进行参数映射查询

返回数据

关闭预处理

跟PHP本地预处理有什么区别呢?
一次处理,终身(此次连接)受益,MySQL语句预处理,比如词法分析等,想象一下,在插入中使用,并且用二进制协议进行数据传输,更加安全效率

左右至MySQL求索

其实也就是转换到MySQL中进行.


#prepare statement
mysql> PREPARE select1 FROM 'SELECT `words`.id FROM `words` WHERE word = ? ORDER BY `id` DESC LIMIT 10 OFFSET 0';
Query OK, 0 rows affected (0.00 sec)
Statement prepared

#bind variable
mysql> set @w1="charm";
Query OK, 0 rows affected (0.00 sec)

#execute
mysql> EXECUTE select1 USING @w1;
+----+
| id |
+----+
|  5 |
+----+
1 row in set (0.00 sec)

wiki的定义

As compared to executing SQL statements directly, prepared statements offer two main advantages:[1]

  • The overhead of compiling and optimizing the statement is incurred only once, although the statement is executed multiple times. Not all optimization can be performed at the time the prepared statement is compiled, for two reasons: the best plan may depend on the specific values of the parameters, and the best plan may change as tables and indexes change over time.[2]
  • Prepared statements are resilient against SQL injection, because parameter values, which are transmitted later using a different protocol, need not be correctly escaped. If the original statement template is not derived from external input, SQL injection cannot occur.

链接https://en.wikipedia.org/wiki/Prepared_statement


发表评论

电子邮件地址不会被公开。 必填项已用*标注