
当尝试在php中使用mysqli::query()方法执行一个包含多个sql语句(例如select * from table1; select * from table2;)的字符串时,mysqli::query()默认只会执行第一个语句并返回其结果。对于后续的语句,它会忽略,这导致开发者在尝试获取第二个查询结果时,会遇到“trying to get property 'num_rows' of non-object”的错误,因为$result变量并非一个有效的查询结果对象。这是mysqli::query()设计上的特性,它旨在处理单个sql语句。
对于需要从多个SELECT语句中获取结果,并且这些SELECT语句的列结构(列数、列名和数据类型)兼容时,最简洁有效的方法是使用SQL的UNION或UNION ALL操作符。UNION操作符用于合并两个或多个SELECT语句的结果集。
UNION与UNION ALL的区别:
示例代码:
<?php
// 假设已包含数据库连接配置
require('configuration.php');
// 创建数据库连接
$conn = new mysqli($db_host, $db_username, $db_password, $db_name);
// 检查连接
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// 使用 UNION ALL 合并两个 SELECT 查询
// 注意:每个 SELECT 语句必须用括号括起来,以确保 UNION 操作符的正确解析
$query = "(SELECT * FROM `table` WHERE `ip` LIKE '1.1.1.1') UNION ALL (SELECT * FROM `table` WHERE `ip` LIKE '2.2.2.2')";
$sql = $query;
$result = $conn->query($sql);
if ($result) { // 检查查询是否成功
if ($result->num_rows > 0) {
// 遍历并输出结果
while($row = $result->fetch_assoc()) {
echo "ID: " . $row["id"]. "<br>IP:" . $row["dedicatedip"]. "<br><br>";
}
} else {
echo "0 results";
}
$result->free(); // 释放结果集
} else {
echo "Error: " . $conn->error; // 输出查询错误信息
}
$conn->close(); // 关闭数据库连接
?>注意事项:
立即学习“PHP免费学习笔记(深入)”;
当需要执行的SQL语句类型不同(例如混合INSERT、UPDATE和SELECT),或者SELECT语句的列结构不兼容,无法使用UNION时,mysqli::multi_query()是更强大的选择。这个方法允许执行一个包含多个由分号分隔的SQL语句的字符串。
mysqli::multi_query()的工作原理:multi_query()执行后,不会立即返回所有查询的结果。你需要使用mysqli::store_result()来获取当前查询的结果集,然后使用mysqli::next_result()来前进到下一个查询的结果。这个过程需要循环进行,直到没有更多的结果集为止。
示例代码:
<?php
// 假设已包含数据库连接配置
require('configuration.php');
// 创建数据库连接
$conn = new mysqli($db_host, $db_username, $db_password, $db_name);
// 检查连接
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// 包含多个 SELECT 语句的查询字符串
$query = "SELECT * FROM `table` WHERE `ip` LIKE '1.1.1.1';";
$query .= "SELECT * FROM `table` WHERE `ip` LIKE '2.2.2.2';";
// 也可以混合其他类型的语句,例如:
// $query .= "UPDATE `table` SET `status` = 'active' WHERE `id` = 1;";
// 执行多语句查询
if ($conn->multi_query($query)) {
$i = 1;
do {
// 存储当前查询的结果集(如果存在)
if ($result = $conn->store_result()) {
echo "<h2>Result Set " . $i . ":</h2>";
if ($result->num_rows > 0) {
// 遍历并输出结果
while ($row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . "<br>IP:" . $row["dedicatedip"] . "<br><br>";
}
} else {
echo "0 results for this query.<br>";
}
$result->free(); // 释放当前结果集
}
// 检查是否有更多结果集
if ($conn->more_results()) {
$i++;
} else {
break; // 没有更多结果集,退出循环
}
} while ($conn->next_result()); // 移动到下一个结果集
} else {
echo "Error: " . $conn->error; // 输出查询错误信息
}
$conn->close(); // 关闭数据库连接
?>注意事项:
立即学习“PHP免费学习笔记(深入)”;
SQL注入防护: 无论是使用UNION还是multi_query,当SQL查询中包含来自用户输入的数据时,都必须使用预处理语句(Prepared Statements)来防止SQL注入。mysqli_prepare()和mysqli_stmt_bind_param()是实现这一目标的关键。虽然multi_query不直接支持预处理语句的批量执行,但对于每个独立的查询,如果其参数来自用户输入,都应单独使用预处理语句。
示例(使用预处理语句): 对于单个查询,例如使用UNION的情况,如果ip值来自用户输入:
// 假设 $ip1 和 $ip2 是用户输入
$ip1 = '1.1.1.1'; // 示例用户输入
$ip2 = '2.2.2.2'; // 示例用户输入
// 构建包含占位符的查询
$query = "(SELECT * FROM `table` WHERE `ip` LIKE ?) UNION ALL (SELECT * FROM `table` WHERE `ip` LIKE ?)";
if ($stmt = $conn->prepare($query)) {
// 绑定参数
$stmt->bind_param("ss", $ip1, $ip2); // "ss" 表示两个字符串参数
// 执行查询
$stmt->execute();
// 获取结果
$result = $stmt->get_result();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo "ID: " . $row["id"]. "<br>IP:" . $row["dedicatedip"]. "<br><br>";
}
} else {
echo "0 results";
}
$stmt->close(); // 关闭预处理语句
} else {
echo "Prepare failed: " . $conn->error;
}性能优化:
在PHP中执行多个MySQL查询时,选择正确的方法至关重要:
无论选择哪种方法,始终将SQL注入防护放在首位,通过使用预处理语句来确保应用程序的安全性。同时,通过合理的索引和查询优化,可以进一步提升多查询操作的性能。
以上就是在PHP中高效执行多个MySQL查询:技巧与实践的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号