在PHP 的數據庫抽象層PDO(PHP Data Objects)中, PDOStatement::rowCount()是一個常用方法,用於返回上一次SQL 執行所影響的行數。然而,很多開發者在不同數據庫驅動中使用時會發現該方法的行為並不一致,甚至在某些場景下根本得不到預期結果。
根據PHP 官方文檔的說明:
對於大多數數據庫, rowCount()僅適用於DELETE 、 INSERT或UPDATE語句。對於SELECT語句,某些數據庫驅動可能會返回受影響的行數,但這並不是PDO 統一行為的一部分。
也就是說, rowCount()的行為取決於底層的數據庫驅動實現。
數據庫類型 | 對SELECT 語句支持rowCount | 對UPDATE/DELETE/INSERT 支持rowCount |
---|---|---|
MySQL | ? 不可靠(通常返回0) | ? 返回受影響行數 |
PostgreSQL | ? 支持 | ? 支持 |
SQLite | ? 支持 | ? 支持 |
MSSQL | ?(依賴驅動實現) | ? |
舉個例子,在MySQL 中:
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->query("SELECT * FROM users");
echo $stmt->rowCount(); // 通常返回 0
但在PostgreSQL 或SQLite 中,可能會返回實際的行數。
主要原因在於數據庫驅動對SQL 的執行方式不同,特別是對於SELECT ,有的驅動不會提前加載所有結果,而是邊遍歷邊取數據,這種情況下它就無法提前知道有多少行。
MySQL 官方驅動( mysqlnd )明確指出:對於SELECT , rowCount()不應該被依賴。
$stmt = $pdo->query("SELECT * FROM users");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$count = count($rows);
echo "共 {$count} 行數據";
或者:
$count = 0;
$stmt = $pdo->query("SELECT * FROM users");
while ($row = $stmt->fetch()) {
$count++;
}
echo "共 {$count} 行數據";
注意:如果數據量大, fetchAll()會佔用大量內存,建議使用循環計數。
$stmt = $pdo->prepare("UPDATE users SET status = 'active' WHERE last_login > NOW() - INTERVAL 7 DAY");
$stmt->execute();
echo "更新了 " . $stmt->rowCount() . " 行";
這類操作的rowCount()通常是可靠的。
可以封裝自己的rowCount 函數,判斷SQL 類型後選擇合適的統計方式:
function safeRowCount(PDOStatement $stmt, $sqlType = 'SELECT') {
if (strtoupper($sqlType) === 'SELECT') {
return count($stmt->fetchAll());
} else {
return $stmt->rowCount();
}
}
這樣可以在不同數據庫驅動中盡量保持行為一致。
PDOStatement::rowCount()的行為不一致是PHP 數據庫開發中常見的坑之一。理解其底層機制,結合SQL 類型選擇合適的處理方式,是寫出兼容性強代碼的關鍵。
如需參考更多示例代碼或分享經驗,可以訪問我們的技術社區: https://gitbox.net/forum 。