在使用PHP 操作數據庫時, PDOStatement::rowCount是一個經常被調用的函數,它返回上一個SQL 操作影響的行數。然而,當你將它與事務(Transaction)結合使用時,其行為可能會引發一些誤解。本文將深入探討該函數在事務中的實際作用、它是否能保障原子性,並提供一些正確的使用建議。
rowCount()是PDOStatement對象的方法之一,通常在執行UPDATE 、 DELETE或INSERT後使用。例如:
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'password');
$stmt = $pdo->prepare("UPDATE users SET status = 'active' WHERE last_login >= :date");
$stmt->execute([':date' => '2024-01-01']);
echo $stmt->rowCount(); // 輸出受影響的行數
需要注意的是,對於SELECT查詢, rowCount()的行為並不可靠,因為它不一定返回結果集中記錄的數量。
事務是為了確保多個操作要么全部成功,要么全部失敗,從而保障操作的原子性。而rowCount()本身只是一個反映受影響行數的統計工具,並不參與事務控制。
來看一個例子:
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare("UPDATE orders SET status = 'processed' WHERE status = 'pending'");
$stmt->execute();
$affected = $stmt->rowCount();
if ($affected === 0) {
throw new Exception("沒有訂單被處理");
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
echo "事務失敗: " . $e->getMessage();
}
在這個例子中, rowCount()是用來判斷是否有行被更新,如果沒有,則人為拋出異常並回滾事務。
這個用法是合理的,但務必理解兩點:
rowCount()的結果是在SQL 執行完畢後計算的,與事務是否提交無關;
如果在UPDATE中沒有匹配行,它返回0,但這並不表示操作出錯,而是邏輯判斷的一部分。
不同的數據庫對rowCount()的支持略有不同。例如:
MySQL支持在UPDATE中返回匹配但未改變的行,除非你啟用了CLIENT_FOUND_ROWS ;
PostgreSQL只返回實際被修改的行;
SQLite對rowCount()的實現更接近於MySQL,但仍需注意細節。
這意味著,如果你在使用rowCount()作為邏輯判斷依據時,務必要結合具體數據庫行為做充分測試。
有些開發者誤以為rowCount()可以用於判斷事務是否“成功”,這是一種常見誤區。事務是否成功,應當由:
所有語句是否正確執行;
是否顯式調用commit() ;
是否未捕捉到異常並調用rollBack() ;
來決定。
而rowCount()只是其中可能的一部分輔助判斷。例如:
if ($stmt->rowCount() < 1) {
// 這可以是業務規則失敗,並不一定代表SQL執行失敗
}
為了更合理地使用rowCount() ,建議遵循以下幾點:
僅用於非SELECT 語句後的邏輯判斷;
不要將其作為事務是否成功的唯一標準;
結合異常處理使用事務,避免依賴返回行數來判斷失敗或成功;
了解所使用數據庫對rowCount()的實際支持行為;
為跨數據庫應用編寫兼容層或適配邏輯;
假設有一個系統需要在更新用戶狀態後,調用外部通知接口:
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare("UPDATE users SET status = 'verified' WHERE email = :email");
$stmt->execute([':email' => '[email protected]']);
if ($stmt->rowCount() === 1) {
// 成功更新,調用外部通知服務
file_get_contents("https://gitbox.net/api/[email protected]");
} else {
throw new Exception("用戶狀態未更新");
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
error_log("事務失敗:" . $e->getMessage());
}
這裡, rowCount()用於判斷是否成功更新一個用戶,僅當成功時才通知外部系統,體現了它在事務中作為“邏輯分支控制點”的典型作用。
PDOStatement::rowCount()是一個有用但容易被誤解的函數。它不能決定事務的原子性,但可以在業務邏輯中起到輔助判斷的作用。正確理解其本質,才能避免在事務處理中的誤用。