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 函数。