PHP 5.1+ 內置 PDO (PHP Data Objects),提供統一接口訪問 MySQL、PostgreSQL、SQLite、Oracle 等 12 種數據庫。當業務從 MySQL 遷移到集群、或升級 Oracle 時,僅需修改 DSN 字串,業務代碼幾乎零改動。本文從安裝、核心 API、預處理語句、異常處理、錯誤碼對照五個維度全面講解。
編輯 php.ini,取消註釋對應擴展:
extension=php_pdo_mysql.dll ; MySQL extension=php_pdo_pgsql.dll ; PostgreSQL extension=php_pdo_sqlite.dll ; SQLite extension=php_pdo_oci.dll ; Oracle ; 重啟 php-fpm / Apache 生效
驗證:php -m | grep pdo 或 phpinfo() 查看 PDO 區塊。

$dsn = 'mysql:host=localhost;dbname=test;charset=utf8mb4';
$user = 'root'; $pass = 'password';
try {
$pdo = new PDO($dsn, $user, $pass);
// 設置錯誤模式為異常(推薦)
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 設置默認獲取模式為關聯數組
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
// 大小寫規範
$pdo->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
} catch (PDOException $e) {
die("連接失敗: " . $e->getMessage());
}
// 直接查詢(僅靜態 SQL)
$stmt = $pdo->query("SELECT * FROM users LIMIT 10");
$users = $stmt->fetchAll(); // 已按 FETCH_ASSOC 返回
print_r($users);
絕對禁止 字串拼接 SQL!prepare() + bindValue()/bindParam() 是鐵律。
// 單條插入
$sql = "INSERT INTO users (name, email, age) VALUES (:name, :email, :age)";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':name', '張三');
$stmt->bindValue(':email', 'zhang@example.com');
$stmt->bindValue(':age', 25, PDO::PARAM_INT);
$stmt->execute();
echo "新用戶 ID: " . $pdo->lastInsertId();
// 批量插入(事務包裹)
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare("INSERT INTO logs (msg, level) VALUES (?, ?)");
foreach ($logs as $log) {
$stmt->execute([$log['msg'], $log['level']]);
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
// 查詢
$stmt = $pdo->prepare("SELECT * FROM users WHERE age > :age AND status = :status");
$stmt->execute([':age' => 18, ':status' => 1]);
while ($row = $stmt->fetch()) {
// 處理每行
}
| 常量 | 返回結構 | 適用場景 | |
|---|---|---|---|
| PDO::FETCH_ASSOC | 關聯數組 ['col'=>'val'] | 最常用,鍵名為列名 | |
| PDO::FETCH_NUM | 索引數組 [0=>'val'] | 高性能、不需列名 | |
| PDO::FETCH_BOTH | 雙重數組(預設) | 記憶體雙倍,慎用 | |
| PDO::FETCH_OBJ | 對象 $row->col | 面向對象代碼風格 | |
| PDO::FETCH_CLASS | 映射到指定類 | ORM/實體映射 | |
| PDO::FETCH_KEY_PAIR | [col1=>col2] | 字典/下拉選項 |
| SQLSTATE | MySQL Code | 含義 | 處理建議 |
|---|---|---|---|
| 00000 | 0 | 成功 | — |
| 42S22 | 1054 | Unknown column | 檢查列名拼寫、反引號 |
| 23000 | 1062 | Duplicate entry (主鍵/唯一鍵衝突) | 業務去重、ON DUPLICATE KEY UPDATE |
| HY000 | 1110 | Column specified twice | SQL 寫錯,列重複 |
| HY000 | 1045 | Access denied | 賬號密碼/權限/主機錯誤 |