许多成熟的数据库都支持预处理语句(Prepared Statements)的概念。它们是什么东西?
你可以把它们想成是一种编译过的要执行的SQL语句模板,可以使用不同的变量参数定制它。
预处理语句具有两个主要的优点:
- 查询只需要被解析(或准备)一次,但可以使用相同或不同的参数执行多次。
- 当查询准备好(Prepared)之后,数据库就会分析,编译并优化它要执行查询的计划。
- 对于复杂查询来说,如果你要重复执行许多次有不同参数的但结构相同的查询,这个过程会占用大量的时间,使得你的应用变慢。
- 通过使用一个预处理语句你就可以避免重复分析、编译、优化的环节。
- 简单来说,预处理语句使用更少的资源,执行速度也就更快。
- 传给预处理语句的参数不需要使用引号,底层驱动会为你处理这个。
- 如果你的应用独占地使用预处理语句,你就可以确信没有SQL注入会发生。
- 然而,如果你仍然在用基于不受信任的输入来构建查询的其他部分,这仍然是具有风险的
正因为预处理语句是如此有用,它成了PDO唯一为不支持此特性的数据库提供的模拟实现。
这使你可以使用统一的数据访问规范而不必关心数据库本身是否具备此特性。
/*
使用预处理语句重复插入数据(1)
此示例演示了一个通过向命名占位符代入一个name和一个value值来执行的INSERT查询
*/
$stmt= $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value); //插入一行
$name= 'one';
$value= 1;
$stmt->execute();//使用不同的值插入另一行
$name= 'two';
$value= 2;
$stmt->execute();
/*
使用预处理语句重复插入数据(2)
此示例演示了一个通过向用?表示的占位符代入一个name和一个value值来执行的INSERT查询
*/
$stmt= $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value); // 插入一行
$name= 'one';
$value= 1;
$stmt->execute(); // 使用不同的值插入另一行
$name= 'two';
$value= 2;
$stmt->execute();
/*
通过预处理语句获取数据
此示例演示使用从表单获取的数据为关键值来执行查询获取数据。用户的输入会被自动添加引号,所以这儿不存在SQL注入攻击的危险。
*/
$stmt= $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if($stmt->execute(array($_GET['name']))) {
while($row= $stmt->fetch()) {
print_r($row);
}
}
其实主流的PHP框架都支持Prepared Statements,而且要简单很多。下面是ThinkPHP模型支持的例子:
// 实例化User模型
$model= D('User');
// 定义预处理传入数据
$data['username'] = 'deeka';
$data['password'] = '123456';
// 数据预处理
if($model->create($data)){
$model->add();
}