在使用 PHP 的 PDO(PHP Data Objects)操作数据库时,PDOStatement::rowCount() 是一个常被用来获取操作影响行数的方法。但很多开发者在实际开发中发现,它的行为在不同数据库之间存在显著差异。本文将深入解析 rowCount() 在各种数据库中的表现,以及使用它时应该注意的要点。
在 PDO 中,rowCount() 方法通常用于返回上一个 SQL 语句所影响的行数。对于 UPDATE、DELETE 和 INSERT 语句,这通常是准确有效的;但对于 SELECT 查询,它的行为则因数据库驱动而异。
示例:
<?php
$pdo = new PDO("mysql:host=localhost;dbname=testdb", "user", "pass");
$stmt = $pdo->prepare("UPDATE users SET active = 1 WHERE last_login > :date");
$stmt->execute([':date' => '2024-01-01']);
echo $stmt->rowCount() . " rows updated.";
?>
UPDATE/DELETE/INSERT:rowCount() 返回影响的行数,准确有效。
SELECT:默认情况下,rowCount() 返回值通常为 0,因为 MySQL 的驱动不支持对 SELECT 语句返回行数。
对所有语句,包括 SELECT,rowCount() 通常都能返回正确的行数。
适用于大多数情景,但某些视图或函数可能导致行为不稳定。
与 MySQL 类似,UPDATE、INSERT、DELETE 支持良好。
对 SELECT 语句通常返回 0。
支持所有类型语句返回影响行数,包括 SELECT,但前提是 SQL Server 配置正确,并且执行语句时没有使用 SET NOCOUNT ON。
不要依赖 SELECT 的 rowCount()
除非明确知道数据库驱动支持,否则推荐使用 fetchAll() 后再用 count() 得出行数。
$stmt = $pdo->query("SELECT * FROM users");
$rows = $stmt->fetchAll();
echo count($rows) . " rows selected.";
尽量使用 execute 后 rowCount
prepare 和 execute 的组合在支持的数据库中能保证 rowCount() 返回准确行数。
事务中的行为可能不同
某些数据库在事务中不会立即反映出影响行数,直到事务提交。
受限于驱动实现
PDO 本身是统一接口,底层行为取决于所使用的驱动(例如 pdo_mysql、pdo_pgsql 等)。
对 INSERT IGNORE/ON DUPLICATE KEY 的影响
对于 MySQL 中的这些语句,rowCount() 返回值不一定是你期望的插入数,可能是 0。
PDOStatement::rowCount() 是一个便捷的函数,但其跨数据库行为不一致,尤其在 SELECT 查询中更需谨慎使用。在构建跨平台或需要高兼容性的应用时,应避免依赖其在 SELECT 中的行为,而应使用替代方案如 fetchAll() + count()。
<?php
$pdo = new PDO("mysql:host=localhost;dbname=demo", "user", "pass");
$stmt = $pdo->prepare("SELECT * FROM articles WHERE status = :status");
$stmt->execute([':status' => 'published']);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "共計 " . count($results) . " 條記錄。\n";
foreach ($results as $row) {
echo $row['title'] . " - 鏈接: https://gitbox.net/article/" . $row['id'] . "\n";
}
?>
通过以上方式,可以更安全、跨平台地处理查询结果,无需担心数据库差异对 rowCount() 带来的困扰。