高效地重复执行查询
问题
希望多次运行同一个查询,每次换入不同的值。
解决方案
用PD0::prepare()建立查询,然后在prepare()返回的已准备语句上调用execute()来运行这个查询。传入prepare()的查询中的占位符被execute()替换为具体的数据。
运行已准备语句
// 数据库连接信息
$user = 'admin'; // 数据库用户名
$password = '123456'; // 数据库密码
// 创建PDO实例,连接到MySQL数据库
$db = new PDO('mysql:host=127.0.0.1;port=3306;dbname=dvwa', $user, $password);
// 注意:这里没有设置错误模式为异常,但在实际应用中推荐这样做
// 例如:$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 准备SQL语句,使用?作为参数的占位符
// 这条语句的目的是从zodiac表中检索element列值为指定值的行的sign列
$st = $db->prepare('SELECT sign FROM zodiac where element LIKE ?');
// 执行SQL语句,并传递一个数组包含第一个参数的值('fire')
// LIKE查询通常需要通配符,但在这个例子中,我们假设element列的值直接匹配'fire'
// 若要匹配包含'fire'的任意文本,应使用'%fire%'作为值的一部分
$st->execute(array('fire'));
// 使用fetch()方法循环获取查询结果
// fetch()每次调用都会返回结果集中的下一行,直到没有更多行为止
while($row = $st->fetch()){
// $row是一个关联数组,键是列名,值是该列的数据
// 但由于我们只选择了一个列(sign),所以也可以使用索引数组访问
// $row[0]获取的是第一列(即sign列)的值
print $row[0] . "
"; // 输出sign列的值,并在每个值后添加换行符
}
// 再次执行相同的SQL语句,但这次传递的参数是'water'
// 注意:这里没有重新准备语句,因为我们已经使用prepare()方法准备好了
// 只需要改变传递给execute()方法的参数值即可
$st->execute(array('water'));
// 同样地,循环获取并输出查询结果
while($row = $st->fetch()){
print $row[0] . "
"; // 输出与'water'元素匹配的sign列的值
}
传入execute()的值称为绑定参数,每个值都与查询中的一个占位符关联(或“绑定”)。绑定参数的两大优点是安全和速度。利用绑定参数,不用再担心SQL注入攻击。PDO会适当地对各个参数加引号和进行转义,使特殊字符“中性化”。另外,执行prepare()时,很多数据库后端会完成查询的一些解析和优化,使得每个execute()调用要比你自行建立一个查询字符串来调用exec()或query()速度更快。
多个占位符
$st = $db->prepare('SELECT sign FROM zodiac where element LIKE ? OR planet LIKE ?');
$st->execute(array('fire','Mercury'));
每次execute()都会用参数值替换?占位符。如果有多个占位符,则按这些参数在查询中出现的顺序放在数组中。
除了?占位符,PDO还支持命名占位符。如果一个查询中有大量占位符,使用命名占位符将有利于阅读。不再使用?,可以在查询中放入一个占位符名(必须以一个冒号开头),然后使用这些占位符名(不带冒号)作为传入execute()的参数数组中的键。
使用命名占位符
$st = $db->prepare('SELECT sign FROM zodiac where element LIKE :element OR planet LIKE :planet');
$st->execute(array('element' => 'fire','planet' => 'Mercury'));
利用命名占位符,查询将更易于阅读,而且可以按任意顺序向execute()提供值。不过要注意,每个占位符名在一个查询中只能出现一次。如果希望一个查询中将同一个值提供多次,需要使用两个不同的占位符名,并在传入execute()的参数数组中将这个值包含两次。
除了?和命名占位符,prepare()还提供了在查询中填入值的第三种方法:bindParam()。这个方法将变量中的值与一个特定的占位符自动关联。
$user = 'admin';
$password = '123456';
$db = new PDO('mysql:host=127.0.0.1;port=3306;dbname=dvwa', $user, $password);
$pairs = array('Mars' => 'water', 'Moon' => 'water', 'Sun' => 'fire');
$st = $db->prepare('SELECT sign FROM zodiac WHERE element LIKE :element AND planet LIKE :planet');
$st->bindParam(':element', $element);
$st->bindParam(':planet', $planet);
foreach($pairs as $planet => $element){
$st->execute();
$row =$st->fetch();
print $row[0] . "
";
}
如果对prepare()使用?占位符,则要提供一个占位符位置作为bindParam()的第一个参数,而不是提供一个参数名。占位符位置从1开始,而不是从0开始。
bindParam()根据值的PHP类型来确定如何处理所提供的值。要强制bindParam()将值处理为某个特定的类型,可以传入一个类型常量作为第三个参数。bindParam()接受的类型常量见表10-2。
$st = $db->prepare('INSERT INTO family (path,contents) VALUES (:path,:contents)');
$st->bindParam(':path', $path);
$st->bindParam(':contents', $fp, PDO::PARAM_LOB);
foreach(glob('./file/*') as $path){
if(($fp = fopen($path, 'r')) !== false){
$st->execute();
fclose($fp);
}else{
echo "无法打开文件: $path";
echo ',br>';
}
//print $row[0] . "
";
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验