共计 2997 个字符,预计需要花费 8 分钟才能阅读完成。
明天这篇文章的内容其实也是十分根底的内容,不过在现代化的开发中,大家都应用框架,曾经很少人会去本人封装或者常常写底层的数据库操作代码了。所以这回咱们就来温习一下数据库中相干扩大中的预处理语句内容。
什么是预处理语句?
预处理语句,能够把它看作是想要运行的 SQL 语句的一种编译过的模板,它能够应用变量参数进行管制。预处理语句能够带来两大益处:
- 查问仅需解析(或预处理)一次,但能够用雷同或不同的参数执行屡次。当查问筹备好后,数据库将剖析、编译和优化执行该查问的打算。对于简单的查问,此过程要花费较长的工夫,如果须要以不同参数多次重复雷同的查问,那么该过程将大大降低应用程序的速度。通过应用预处理语句,能够防止反复剖析 / 编译 / 优化周期。简言之,预处理语句占用更少的资源,因此运行得更快。
- 提供给预处理语句的参数不须要用引号括起来,驱动程序会主动解决。如果应用程序只应用预处理语句,能够确保不会产生 SQL 注入。(然而,如果查问的其余局部是由未本义的输出来构建的,则仍存在 SQL 注入的危险)。
上述内容是摘自官网文档的阐明,但其实预处理语句带给咱们最直观的益处就是可能无效地预防 SQL 注入。对于 SQL 注入的内容咱们未来在学习 MySQL 的时候再进行深刻的学习,这里就不过多地介绍了,反正预处理语句就是能够实现这项工作就好了。
PDO 操作预处理语句
在 PHP 的扩大中,PDO 曾经是支流的外围数据库扩大库,天然它对预处理语句的反对也是十分全面的。
$pdo = new PDO('mysql:host=localhost;port=3306;dbname=blog_test', 'root', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// :xxx 占位符
$stmt = $pdo->prepare("insert into zyblog_test_user (username, password, salt) values (:username, :password, :salt)");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->bindParam(':salt', $salt);
$username = 'one';
$password = '123123';
$salt = 'aaa';
$stmt->execute();
$username = 'two';
$password = '123123';
$salt = 'bbb';
$stmt->execute();
在代码中,咱们应用 prepare() 办法定义预处理语句,这个办法会返回一个 PDOStatement 对象。在预处理的语句内应用 :xxx 这样的占位符号,并在内部应用 PDOStatement 对象的 bindParam() 办法为这些占位符绑定上变量。最初通过 execute() 来真正地执行 SQL 语句。
从这段代码中,咱们就能够看到预处理语句的两大劣势的体现。首先是占位符,应用占位符之后,咱们就不必在 SQL 语句中去写单引号,单引号往往就是 SQL 注入的次要破绽起源。bindParam() 办法会主动地转换绑定数据的类型。当然,bindParam() 办法也能够在可选的参数中指定绑定的数据类型,这样就能让咱们的代码更加平安了,大家能够查阅相干的文档。
另一个劣势就是模板的能力,咱们只定义了一个 PDOStatement 对象,而后通过扭转数据的内容,就能够屡次地应用 execute() 办法去执行预处理语句。
占位符还有另一种写法,就是应用一个问号来作为占位符号,在这种状况下,bindParam() 办法的键名就要应用数字下标了。这里须要留神的是,数字下标是从 1 开始的。
// ? 占位符
$stmt = $pdo->prepare("insert into zyblog_test_user (username, password, salt) values (?, ?, ?)");
$stmt->bindParam(1, $username);
$stmt->bindParam(2, $password);
$stmt->bindParam(3, $salt);
$username = 'three';
$password = '123123';
$salt = 'ccc';
$stmt->execute();
在咱们的查问中,也是能够不便地应用预处理语句的性能进行数据查问的。在这里,咱们间接应用 execute() 来为占位符传递参数。
// 查问获取数据
$stmt = $pdo->prepare("select * from zyblog_test_user where username = :username");
$stmt->execute(['username'=>'one']);
while($row = $stmt->fetch()){print_r($row);
}
mysqli 操作预处理语句
虽说支流是 PDO,而且大部分框架中应用的也是 PDO,但咱们在写脚本,或者须要疾速地测试一些性能的时候,还是会应用 mysqli 来疾速地开发。当然,mysqli 也是反对预处理语句相干性能的。
// mysqli 预处理
$conn = new mysqli('127.0.0.1', 'root', '','blog_test');
$username = 'one';
$stmt = $conn->prepare("select username from zyblog_test_user where username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
echo $stmt->bind_result($unames);
var_dump($unames);
while ($stmt->fetch()) {printf("%s\n", $unames);
}
能够看出,mysqli 除了办法名不同之外,绑定参数的键名也不齐全的雷同,这里咱们应用的是问号占位,在 bind_param() 办法中,是应用 s 来示意符号地位,如果是多个参数,就要写成 sss… 这样。
总结
预处理语句的能力在当初的框架中都曾经帮咱们封装好了,其实咱们并不需要太关怀,就像 Laravel 中应用 DB::select() 进行数据库操作时,咱们就能够看到预处理语句的利用。
大家能够自行查阅 vendor/laravel/framework/src/Illuminate/Database/Connection.php 中的 select() 办法。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202008/source/PHP%E4%B8%AD%E6%93%8D%E4%BD%9C%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E9%A2%84%E5%A4%84%E7%90%86%E8%AF%AD%E5%8F%A5.php
参考文档:
https://www.php.net/manual/zh/pdo.prepared-statements.php
===========
各自媒体平台均可搜寻【硬核项目经理】