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

PHP 使用 PDO 連接並查詢 SQL Server / MySQL 資料庫完整指南

     編輯:PHP 綜合知識

PDO (PHP Data Objects) 提供統一介面存取多種資料庫,是現代 PHP 專案的標準資料層。本文涵蓋 PDO 連接 MySQL 與 SQL Server (PDO_SQLSRV) 的完整設定、查詢執行、預處理、錯誤處理、進階封裝與最佳實踐。

核心優勢

  • 資料庫無關性: 更換資料庫只需改 DSN,業務邏輯不變。
  • 安全性: 預處理語句徹底防止 SQL 注入。
  • 效能: 原生驅動、支援預處理快取、交易控制。
  • 物件導向: 例外處理、可繼承擴充、型別提示友善。

1. 連接 MySQL (PDO_MYSQL)

<?php
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8mb4';
$user = 'root';
$pass = 'password';

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false, // 使用真實預處理
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
    exit('MySQL 連線失敗:' . $e->getMessage());
}

// 簡單查詢
foreach ($pdo->query('SELECT * FROM `users`') as $row) {
    print_r($row);
}
?>

2. 連接 SQL Server (PDO_SQLSRV)

<?php
// 需安裝 Microsoft ODBC Driver 17/18 + php_pdo_sqlsrv.dll
$dsn = 'sqlsrv:Server=127.0.0.1;Database=master;ConnectionPooling=1';
$user = 'sa';
$pass = 'password';

$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
    echo 'SQL Server 版本:' . $pdo->query('SELECT @@VERSION')->fetchColumn();
} catch (PDOException $e) {
    exit('SQL Server 連線失敗:' . $e->getMessage());
}
?>

3. 進階封裝:自訂 PDO 子類別

<?php
class Database extends PDO {
    public function __construct(array $config) {
        $dsn = $config['driver'] . ':host=' . $config['host'] . ';dbname=' . $config['dbname'];
        if (!empty($config['charset'])) $dsn .= ';charset=' . $config['charset'];

        parent::__construct($dsn, $config['user'], $config['pass'], [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false,
        ]);
    }

    // 安全查詢:自動記錄慢查詢、參數綁定
    public function query($sql, array $params = []) {
        $stmt = $this->prepare($sql);
        $stmt->execute($params);
        return $stmt;
    }

    // 單筆查詢
    public function fetchOne($sql, array $params = []) {
        return $this->query($sql, $params)->fetch();
    }

    // 全部查詢
    public function fetchAll($sql, array $params = []) {
        return $this->query($sql, $params)->fetchAll();
    }

    // 交易執行器
    public function transaction(callable $callback) {
        $this->beginTransaction();
        try {
            $result = $callback($this);
            $this->commit();
            return $result;
        } catch (\Throwable $e) {
            $this->rollBack();
            throw $e;
        }
    }
}

// 使用範例
$config = [
    'driver' => 'mysql',
    'host'   => 'localhost',
    'dbname' => 'test',
    'user'   => 'root',
    'pass'   => 'password',
    'charset'=> 'utf8mb4',
];

$db = new Database($config);

// 參數化查詢
$users = $db->fetchAll('SELECT * FROM `users` WHERE `status` = ? AND `role` = ?', [1, 'admin']);

// 交易
$db->transaction(function($db) {
    $db->query('UPDATE `accounts` SET `balance` = `balance` - ? WHERE `id` = ?', [500, 1]);
    $db->query('UPDATE `accounts` SET `balance` = `balance` + ? WHERE `id` = ?', [500, 2]);
    $db->query('INSERT INTO `transfers` (`from`,`to`,`amount`) VALUES (?,?,?)', [1,2,500]);
});
?>

4. 執行結果與影響筆數辨析

方法回傳適用場景取得影響筆數
PDO::exec()int無結果集的 INSERT/UPDATE/DELETE直接回傳
PDO::query()PDOStatementSELECT、SHOW 等有結果集不適用
PDOStatement::execute()bool預處理語句執行$stmt->rowCount()

5. 錯誤處理模式

<?php
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 推薦:拋出例外

try {
    $stmt = $pdo->prepare('SELECT * FROM `table` WHERE `id` = ?');
    $stmt->execute([$id]);
    $row = $stmt->fetch();
} catch (PDOException $e) {
    // $e->getCode()       => SQLSTATE 錯誤代碼 (如 23000 完整性約束違反)
    // $e->getMessage()    => 完整錯誤訊息
    // $e->errorInfo       => array(SQLSTATE, Driver Code, Driver Message)
    error_log('DB Error: ' . $e->getMessage());
    // 回傳友善錯誤給前端
    http_response_code(500);
    echo json_encode(['error' => '資料庫操作失敗']);
}
?>

6. 常見陷阱與解決

現象原因解決
預處理不生效、仍被注入ATTR_EMULATE_PREPARES = true (預設)設定 false 強制原生預處理
SELECT rowCount() 回傳 0MySQL 驅動不支援 SELECT 筆數統計改用 SELECT COUNT(*) 或 fetchAll() 後 count()
長連接導致 "MySQL server has gone away"連線超過 wait_timeout 被斷開啟用 ATTR_PERSISTENT 或重連邏輯
中文亂碼DSN 缺 charset / 連線未設定編碼MySQL: charset=utf8mb4;SQL Server: CharacterSet=UTF-8

7. PDO 發展路線圖

  • PHP 5.1:引入 PDO 核心
  • PHP 5.3:PDO 成為核心擴充,預設啟用
  • PHP 7.0:效能大幅提升、型別宣告支援
  • PHP 8.0+:PDO::PARAM_BOOL、PDO::FETCH_KEY_PAIR、錯誤類別層級化
  • 未來:非同步查詢 (PDO Async)、更完善的型別對應

小結

PDO 是 PHP 資料庫存取的基石。掌握「DSN 設定」、「錯誤模式設為例外」、「關閉模擬預處理」、「善用交易與自訂封裝」四大要訣,即能寫出安全、高效、可維護的資料層程式碼。無論 MySQL、PostgreSQL、SQL Server、SQLite、Oracle,PDO 都提供一致的開發體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved