使用 SO 上其他地方的示例来更好地捕获“隐藏”错误。虽然下面的代码将捕获并返回错误,但是否可以改进它以报告发生错误的查询?
使用下面的代码,输出是:
Columns: 18
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRO inventory' at line 1
正在测试的代码:
$query = "SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20;";
$query .= "SELECT * FRO inventory"; // With error
$ord = array();
$invent = array();
if(mysqli_multi_query($link, $query)) {
do {
// fetch results
if($result = mysqli_store_result($link)) {
echo 'Columns: ' . mysqli_field_count($link) . "<br>";
while($row = mysqli_fetch_assoc($result)) {
if(count($row) > 17)
$orders[] = $row;
elseif(count($row) == 6)
$inv[] = $row;
}
}
if(!mysqli_more_results($link))
break;
if(!mysqli_next_result($link)) {
// report error
echo 'Error: ' . mysqli_error($link);
break;
}
} while(true);
mysqli_free_result($result);
}
最佳答案
这种方法不仅可以提高错误消息的质量,还可以改进您处理结果集的方式。
$q["Orders"] = "SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20";
$q["Inventory"] = "SELECT * FRO inventory";
if (!$link = mysqli_connect("host", "user", "pass", "db")) {
echo "Failed to connect to MySQL: " , mysqli_connect_error();
} elseif (mysqli_multi_query($link, implode(';', $q))) {
do {
$q_key = key($q); // current query's key name (Orders or Inventory)
if ($result = mysqli_store_result($link)) { // if a result set... SELECTs do
while ($row = mysqli_fetch_assoc($result)) { // if one or more rows, iterate all
$rows[$q_key][] = $row;
}
mysqli_free_result($result);
echo "<div><pre>" . var_export($rows[$q_key], true) . "</pre></div>";
}
} while (next($q) && mysqli_more_results($link) && mysqli_next_result($link));
}
if ($mysqli_error = mysqli_error($link)) { // check & declare variable in same step to avoid duplicate func call
echo "<div style=\"color:red;\">Query Key = " , key($q) , ", Query = " , current($q) , ", Syntax Error = $mysqli_error</div>";
}
第一次查询时出错:
如果您的第一个查询尝试访问指定数据库中不存在的表,例如:ordersXYZ
数组 $rows
不会存在,没有 var_export()
将发生,您将看到此响应:
Query Key = Orders, Query = SELECT * FROM ordersXYZ WHERE location='IN' ORDER BY orderNum DESC LIMIT 20, Syntax Error = Table '[someDB].ordersXYZ' doesn't exist
第二次查询出错:
如果您的第一个查询成功,但您的第二个查询尝试访问一个不存在的表,例如:inventory2
$rows["Orders"]
将保存所需的行数据并且将是 var_export()
'编辑,$row["Inventory"]
将不存在,您将看到此响应:
Query Key = Inventory, Query = SELECT * FROM inventory2, Syntax Error = Table '[someDB].inventory2' doesn't exist
没有错误:
如果两个查询都没有错误,您的 $rows
数组将填充所需的数据和 var_export()
'ed,不会有错误响应。将查询到的数据保存在$rows
中, 您可以从 $rows["Orders"]
访问您想要的内容和 $rows["Inventory"]
.
注意事项:
您可能会注意到我同时进行了变量声明和条件检查,这使代码更加简洁,但一些开发人员更愿意避免这种情况。
因为我的方法使用
implode()
在elseif
上有一个分号行,请确保不要在查询中添加尾随分号。这组查询总是返回一个结果集,因为所有都是 SELECT 查询,如果您有一个混合的查询集合
affect_rows
,您可能会在此链接 ( https://stackoverflow.com/a/22469722/2943403 ) 中找到一些有用的信息。mysqli_multi_query()
一旦出现错误,将立即停止运行查询。如果您希望捕获“所有”错误,您会发现永远不会超过一个。像 OP 的问题和解决方案那样编写条件断点是不可取的。虽然在其他情况下可以正确使用自定义断点,但对于这种情况,断点应位于
while()
内部。do()
的声明 block 。返回零行的查询不会导致错误消息——它只是不会在
$rows
中创建任何子数组。因为while()
不会进入循环。通过使用
key()
函数,OP 的if/elseif
可以避免对每个结果集行中的列进行计数的条件。这是更好的做法,因为在某些情况下,每次迭代都运行一个条件可能会变得昂贵。请注意,数组指针在$q
内部被提前在每个do()
的末尾迭代。这是您在 php 手册页上找不到的附加技术;它允许key()
按预期工作。当然还有
<div><pre>var_export()...</pre></div>
行可以从您的工作代码中删除——这纯粹是为了演示。如果您要在此代码块之后运行任何更多的查询以重用变量,请务必清除所有使用的变量,以免残留数据干扰。例如
$mysqli_error=null; // clear errors
&reset($q); // reset array pointer
.自行决定注意这个有些模糊的警告:http://php.net/manual/en/mysqli.use-result.php :
One should not use mysqli_use_result() if a lot of processing on the client side is performed, since this will tie up the server and prevent other threads from updating any tables from which the data is being fetched.
关于php - 如何使用 mysqli_multi_query 识别导致错误的查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12232974/