首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP PDO::exec() 詳解:執行無結果集 SQL(INSERT/UPDATE/DELETE)與影響行數獲取

     編輯:PHP 相關知識

PHP PDO::exec() 詳解

PDO::exec() 專門用於執行 不返回結果集 的 SQL 語句:INSERT、UPDATE、DELETE、CREATE TABLE、TRUNCATE 等。返回值為 受影響行數(整數),失敗返回 false。

語法與核心區別

方法用途返回值典型場景
exec()無結果集 SQL受影響行數 (int) / falseINSERT/UPDATE/DELETE/DDL
query()有結果集 SQLPDOStatement 對象 / falseSELECT/SHOW/DESCRIBE
prepare() + execute()參數化/重複執行bool (execute) / PDOStatement所有場景(推薦首選)

完整示例:寫入數據並驗證

<?php
header('Content-Type: text/html; charset=utf-8');

$dsn = 'mysql:host=localhost;dbname=test;charset=utf8mb4';
$pdo = new PDO($dsn, 'root', '123456', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 拋出異常,不用手動檢查錯誤碼
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false, // 使用原生預處理
]);

// 1. 執行 INSERT,獲取影響行數
$username = 'liming';
$password = password_hash('123456', PASSWORD_DEFAULT); // 安全:密碼哈希
$regdate = time();

$sql = "INSERT INTO userlist (username, password, regdate) VALUES (?, ?, ?)";
$affected = $pdo->exec($sql); // ❌ 錯誤:exec 不支持參數綁定,會字面執行 "?"

// 正確寫法:prepare + execute
$stmt = $pdo->prepare($sql);
$stmt->execute([$username, $password, $regdate]);
$affected = $stmt->rowCount(); // 受影響行數

echo "寫入 {$affected} 條記錄!<hr>";

// 2. 獲取自增 ID(INSERT 專用)
$lastId = $pdo->lastInsertId();
echo "新記錄 ID: {$lastId}<hr>";

// 3. 查詢驗證(使用 query 返回 PDOStatement)
$stmt = $pdo->query("SELECT * FROM userlist ORDER BY id DESC LIMIT 5");
while ($row = $stmt->fetch()) {
    echo "用戶名: {$row['username']}  ";
    echo "註冊時間: " . date('Y-m-d H:i:s', $row['regdate']) . "<br>";
}

關鍵陷阱:exec() 不支持參數綁定

// ❌ 錯誤:SQL 注入風險,且 ? 會被當作字面字符
$pdo->exec("INSERT INTO t (c) VALUES (?)");

// ✅ 正確:prepare + execute 參數化
$stmt = $pdo->prepare("INSERT INTO t (c) VALUES (?)");
$stmt->execute([$value]);

結論:生產代碼中幾乎不應直接使用 exec(),除非執行純靜態 DDL(如 CREATE TABLE、TRUNCATE)。所有帶參數的寫操作統一用 prepare() + execute()。

事務控制:保證數據一致性

try {
    $pdo->beginTransaction();
    
    $pdo->prepare("INSERT INTO orders (user_id, total) VALUES (?, ?)")->execute([1, 99.9]);
    $orderId = $pdo->lastInsertId();
    
    $pdo->prepare("INSERT INTO order_items (order_id, product_id, qty) VALUES (?, ?, ?)")
        ->execute([$orderId, 101, 2]);
    $pdo->prepare("UPDATE products SET stock = stock - 2 WHERE id = 101")->execute();
    
    $pdo->commit();
    echo "訂單創建成功";
} catch (Throwable $e) {
    $pdo->rollBack();
    echo "失敗回滾: " . $e->getMessage();
}

批量插入優化:單條 execute vs 多值 INSERT

// 方案 A:循環 prepare + execute(慢,每條往返)
foreach ($rows as $row) {
    $stmt->execute($row);
}

// 方案 B:構建多值 INSERT(快,單次往返)
$placeholders = implode(',', array_fill(0, count($rows), '(?,?,?)'));
$sql = "INSERT INTO logs (level, message, created_at) VALUES {$placeholders}";
$params = array_merge(...$rows); // 展平為一維數組
$pdo->prepare($sql)->execute($params);

錯誤處理模式對比

模式設置代碼風格推薦度
靜默ATTR_ERRMODE => SILENT手動檢查 $stmt->errorCode()❌ 易漏檢
警告ATTR_ERRMODE => WARNING觸發 E_WARNING,繼續執行❌ 非致命
異常ATTR_ERRMODE => EXCEPTION拋出 PDOException,try-catch 捕獲✅ 強制處理

總結

  1. exec() 僅用於無參數 DDL,返回影響行數。
  2. 所有 DML(增刪改)必須使用 prepare() + execute() 參數化,防注入、支援二進制數據、可重複執行。
  3. INSERT 後用 lastInsertId() 獲取自增 ID。
  4. 啟用 ERRMODE_EXCEPTION + try-catch 統一錯誤處理。
  5. 批量寫入構建多值 INSERT,單次往返提升 10-100 倍吞吐。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved