PHP PDOStatement::nextRowset 方法
最后修改于 2025 年 4 月 19 日
PDOStatement::nextRowset 方法允许处理来自存储过程或批处理查询的多个结果集。它会前进到下一个结果集。
基本定义
当一个语句返回多个结果集时,PDOStatement::nextRowset 将游标移动到下一个结果集。这在存储过程调用中很常见。
语法:public PDOStatement::nextRowset(): bool。成功时返回 true,如果没有更多结果集则返回 false。失败时抛出 PDOException。
简单的 nextRowset 示例
此示例演示了 nextRowset 与存储过程的基本用法。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("CALL get_multiple_results()");
// Process first result set
while ($row = $stmt->fetch()) {
echo "User: {$row['name']}\n";
}
// Move to next result set
if ($stmt->nextRowset()) {
while ($row = $stmt->fetch()) {
echo "Product: {$row['product_name']}\n";
}
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
此代码调用一个返回两个结果集的存储过程。我们处理第一个结果集,然后使用 nextRowset 访问第二个结果集。请务必检查 nextRowset 的返回值。
处理多个结果集
此示例展示了如何处理查询中数量不确定的结果集。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("SELECT * FROM users; SELECT * FROM products;");
$resultSetNumber = 1;
do {
echo "Result Set #$resultSetNumber:\n";
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
print_r($row);
}
echo "\n";
$resultSetNumber++;
} while ($stmt->nextRowset());
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
此代码在一个查询中执行两个 SELECT 语句。do-while 循环处理每个结果集,直到 nextRowset 返回 false。每次迭代处理一个结果集。
组合 INSERT 和 SELECT
此示例展示了如何将 nextRowset 与组合的 INSERT 和 SELECT 查询一起使用。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("
INSERT INTO logs (message) VALUES ('Test log entry');
SELECT * FROM logs ORDER BY created_at DESC LIMIT 5;
");
echo "Insert completed\n";
if ($stmt->nextRowset()) {
echo "Recent log entries:\n";
while ($row = $stmt->fetch()) {
echo "{$row['created_at']}: {$row['message']}\n";
}
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
此代码执行一个 INSERT,然后执行一个 SELECT。INSERT 不返回行,因此我们使用 nextRowset 跳转到 SELECT 结果集。这种模式对于审计日志记录非常有用。
带输出参数的存储过程
此示例演示了 nextRowset 与带输出参数的存储过程的用法。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("CALL get_user_stats(?, @total_users, @avg_age)");
$stmt->execute(['active']);
// First result set - user data
while ($row = $stmt->fetch()) {
echo "User: {$row['name']}, Age: {$row['age']}\n";
}
// Move to next result set - output parameters
if ($stmt->nextRowset()) {
$output = $pdo->query("SELECT @total_users AS total_users, @avg_age AS avg_age")->fetch();
echo "Total users: {$output['total_users']}\n";
echo "Average age: {$output['avg_age']}\n";
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
此代码调用一个首先返回用户数据,然后返回输出参数的存储过程。我们处理用户数据,然后在使用输出参数之前使用 nextRowset。输出参数在过程调用后需要单独查询。
nextRowset 的错误处理
此示例展示了处理多个结果集时的正确错误处理方法。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("
SELECT * FROM valid_table;
SELECT * FROM non_existent_table;
");
// Process first result set
echo "First result set:\n";
while ($row = $stmt->fetch()) {
print_r($row);
}
// Attempt to move to next result set
try {
if (!$stmt->nextRowset()) {
echo "No more result sets\n";
} else {
echo "Second result set:\n";
while ($row = $stmt->fetch()) {
print_r($row);
}
}
} catch (PDOException $e) {
echo "Error moving to next result set: " . $e->getMessage();
}
} catch (PDOException $e) {
echo "Query error: " . $e->getMessage();
}
此代码展示了用于处理错误的嵌套 try-catch 块。第二个查询失败了,但我们捕获了来自 nextRowset 的异常。在处理不可信查询时,始终将 nextRowset 调用包装在 try-catch 中。
SQL Server 多个结果集
此示例演示了 nextRowset 与 SQL Server 的多个结果集用法。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('sqlsrv:Server=localhost;Database=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("
SELECT * FROM customers WHERE region = 'North';
SELECT * FROM orders WHERE order_date > '2023-01-01';
SELECT COUNT(*) AS product_count FROM products;
");
$resultNumber = 1;
do {
echo "Result Set #$resultNumber:\n";
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);
$resultNumber++;
} while ($stmt->nextRowset());
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
SQL Server 经常返回多个结果集。此代码执行三个查询并处理所有结果。fetchAll 用于检索每个结果集的所有行。循环继续,直到 nextRowset 返回 false。
将 nextRowset 与 Column Count 结合使用
此示例展示了如何将 columnCount 与 nextRowset 一起使用来处理动态结果。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query("
SELECT id, name FROM users LIMIT 2;
SELECT product_id, product_name, price FROM products LIMIT 3;
");
$setNumber = 1;
do {
$colCount = $stmt->columnCount();
echo "Result Set #$setNumber ($colCount columns):\n";
if ($colCount > 0) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
print_r($row);
}
} else {
echo "No columns in this result set\n";
}
$setNumber++;
} while ($stmt->nextRowset());
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
此代码在处理每个结果集之前检查 columnCount。某些结果集可能没有列(例如 INSERT 语句之后)。该示例在批处理中处理了返回数据和不返回数据的查询。
最佳实践
- 检查返回值:始终验证 nextRowset 的布尔返回值。
- 错误处理:将其包装在 try-catch 中,因为它可能抛出异常。
- 资源清理:完成所有结果集处理后关闭语句。
- 性能:避免查询中不必要的结果集。
- 文档:清晰记录多结果存储过程。
来源
本教程涵盖了 PDOStatement::nextRowset 方法,并通过实际示例展示了不同的数据库场景和正确的错误处理。
作者
列出 所有 PHP PDO 函数。