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

PDO 入門指南:數據庫抽象層的正確打開方式,告別 mysql_* 時代

     編輯:PHP 相關知識

PDO 入門指南:數據庫抽象層的正確打開方式,告別 mysql_* 時代

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 區塊。

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 注入的核心

絕對禁止 字串拼接 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()) {
  // 處理每行
}

四、獲取模式(Fetch Mode)詳解

可用 $stmt->setFetchMode(PDO::FETCH_ASSOC) 或 $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, ...) 全局設置。

五、異常處理與錯誤碼對照

try {
  $pdo = new PDO($dsn, $user, $pass);
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $count = $pdo->exec("INSERT INTO info SET name='test', job=1");
} catch (PDOException $e) {
  // 連接/準備/執行階段異常
  echo "Message: " . $e->getMessage(); // 如 SQLSTATE[HY000] [1045] Access denied
  echo "Code: " . $e->getCode();        // 1045
  echo "File: " . $e->getFile();
  echo "Line: " . $e->getLine();
  echo "Trace: " . $e->getTraceAsString();
}

常見 SQLSTATE / MySQL 錯誤碼:

常量返回結構適用場景
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]字典/下拉選項

執行 exec()/query() 後,亦可用 $pdo->errorCode()、$pdo->errorInfo() 獲取最近一次錯誤(非異常模式下)。

六、進階技巧

  • 持久連接:DSN 加 pdo_mysql.connection_persistent=1 或構造函數第 4 參數 [PDO::ATTR_PERSISTENT => true],減少握手開銷,但需注意連接數上限。
  • 調試 SQL:$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false) 使用真預處理,配合 $stmt->debugDumpParams() 打印綁定參數。
  • 大數據流:PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false 非緩衝查詢,逐行處理百萬級結果集不爆記憶體。

掌握 PDO,就是掌握了 PHP 數據庫開發的「通用鑰匙」,無論未來遷移何種數據庫,業務層代碼都能平滑過渡。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
SQLSTATEMySQL Code含義處理建議
000000成功—
42S221054Unknown column檢查列名拼寫、反引號
230001062Duplicate entry (主鍵/唯一鍵衝突)業務去重、ON DUPLICATE KEY UPDATE
HY0001110Column specified twiceSQL 寫錯,列重複
HY0001045Access denied賬號密碼/權限/主機錯誤