核心函數對比
| 方法 | 適用操作 | 返回值含義 | 注意事項 |
mysql_affected_rows() | INSERT/UPDATE/DELETE | 受影響行數 | 舊擴展,PHP 7 移除 |
mysqli_affected_rows() | INSERT/UPDATE/DELETE | 受影響行數 | 推薦,面向對象 $mysqli->affected_rows |
PDO::rowCount() | INSERT/UPDATE/DELETE | 受影響行數 | SELECT 不可靠,官方不建議用於 SELECT |
SQL ROW_COUNT() | INSERT/UPDATE/DELETE | 受影響行數 | 會話級,緊跟寫操作調用 |
SQL FOUND_ROWS() | SELECT (配合 SQL_CALC_FOUND_ROWS) | 匹配總行數(忽略 LIMIT) | 需在 SELECT 前加 SQL_CALC_FOUND_ROWS |
mysqli 實戰示例
<?php
$mysqli = new mysqli("localhost", "root", "pass", "test");
$mysqli->set_charset("utf8mb4");
// UPDATE
$mysqli->query("UPDATE users SET status = 1 WHERE status = 0");
echo "更新行數: " . $mysqli->affected_rows . "<br>"; // 正確
// DELETE
$mysqli->query("DELETE FROM logs WHERE created_at < '2023-01-01'");
echo "刪除行數: " . $mysqli->affected_rows . "<br>";
// INSERT
$mysqli->query("INSERT INTO users (name) VALUES ('test')");
echo "新增 ID: " . $mysqli->insert_id . ", 影響行數: " . $mysqli->affected_rows . "<br>";
// 事務中
$mysqli->begin_transaction();
$mysqli->query("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$mysqli->query("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
echo "事務中第一條影響: " . $mysqli->affected_rows; // 僅反映最後一條語句
$mysqli->commit();
PDO 實戰示例
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->prepare("UPDATE products SET stock = stock - ? WHERE id = ? AND stock >= ?");
$stmt->execute([5, 101, 5]);
echo "扣減庫存行數: " . $stmt->rowCount(); // 1 成功,0 庫存不足
// 批量插入
$pdo->beginTransaction();
$stmt = $pdo->prepare("INSERT INTO logs (msg) VALUES (?)");
foreach ($messages as $msg) {
$stmt->execute([$msg]);
}
$pdo->commit();
// 注意:rowCount() 僅反映最後一次 execute
SQL 層面 ROW_COUNT() 使用場景
-- 存儲過程中
UPDATE orders SET status = 'paid' WHERE id = 123;
SELECT ROW_COUNT() AS updated_rows; -- 返回 1 或 0
-- 觸發器中
CREATE TRIGGER after_order_update
AFTER UPDATE ON orders
FOR EACH ROW BEGIN
IF ROW_COUNT() > 0 THEN
INSERT INTO order_logs (order_id, action) VALUES (NEW.id, 'status_change');
END IF;
END;
常見誤區與避坑
- SELECT 使用 rowCount():PDO 的
rowCount() 對 SELECT 返回值未定義(驅動相關),統計總數請用 SELECT COUNT(*) 或 SQL_CALC_FOUND_ROWS + FOUND_ROWS()。
- REPLACE INTO 影響行數:若鍵衝突刪除舊行再插入,返回 2(1 delete + 1 insert)。
- INSERT ... ON DUPLICATE KEY UPDATE:新增返回 1,更新返回 2,無變化返回 0。
- 事務中 affected_rows:僅反映最後一條語句,需逐條檢查或用
ROW_COUNT()。
- 舊 mysql_affected_rows() 異常:若遇到返回 -1,通常是連接斷開或 SQL 語法錯誤,建議遷移至 mysqli/PDO。
兼容性封裝函數(舊項目維護用)
function get_affected_rows($link = null) {
if (function_exists('mysqli_affected_rows')) {
return $link ? mysqli_affected_rows($link) : mysqli_affected_rows($GLOBALS['mysqli_link']);
}
if (function_exists('mysql_affected_rows')) {
return $link ? mysql_affected_rows($link) : mysql_affected_rows();
}
// PDO 情況下需傳入 Statement 對象
return -1;
}
總結
- 新項目:**mysqli->affected_rows** 或 **PDOStatement->rowCount()**(僅寫操作)。
- 存儲過程/觸發器:**ROW_COUNT()**。
- 分頁總數:**SQL_CALC_FOUND_ROWS + FOUND_ROWS()** 或單獨
COUNT(*)。
- 永遠檢查返回值,0 代表「無匹配/無變化」而非錯誤,錯誤需捕獲異常/errno。