ODBC (Open Database Connectivity) 提供統一介面訪問異構數據庫。PHP 通過 odbc_* 函數族支援 ODBC,適合連接 SQL Server、Access、DB2、Sybase 等無原生驅動的數據庫。本文涵蓋 DSN 配置、連接參數、查詢執行、錯誤處理、預處理語句、事務控制等實戰內容。
MyAppDB、描述、SQL Server 地址<?php
// 連接字符串方式 (無需預建 DSN)
$connStr = "Driver={ODBC Driver 17 for SQL Server};Server=192.168.1.100,1433;Database=MyDB;Uid=sa;Pwd=Passw0rd;Encrypt=yes;TrustServerCertificate=yes;";
$conn = odbc_connect($connStr, '', '', SQL_CUR_USE_ODBC);
// 或使用系統 DSN
$conn = odbc_connect('MyAppDB', 'sa', 'Passw0rd', SQL_CUR_USE_ODBC);
if (!$conn) {
die("連接失敗: " . odbc_errormsg());
}
echo "連接成功\n";
// 簡單查詢
$sql = "SELECT id, username, email, created_at FROM users WHERE status = 1";
$result = odbc_exec($conn, $sql);
if (!$result) {
die("查詢失敗: " . odbc_errormsg($conn));
}
// 獲取欄位信息
$numFields = odbc_num_fields($result);
for ($i = 1; $i <= $numFields; $i++) {
echo "Field $i: " . odbc_field_name($result, $i) . " (" . odbc_field_type($result, $i) . ")\n";
}
// 逐行獲取 (關聯陣列)
while ($row = odbc_fetch_array($result)) {
echo "ID: {$row['id']}, User: {$row['username']}, Email: {$row['email']}\n";
}
// 釋放結果
odbc_free_result($result);
// 關閉連接
odbc_close($conn);
<?php
$conn = odbc_connect('MyAppDB', 'sa', 'Passw0rd');
// 準備語句
$stmt = odbc_prepare($conn, "SELECT * FROM users WHERE username = ? AND status = ?");
if (!$stmt) die("Prepare 失敗: " . odbc_errormsg($conn));
// 綁定參數並執行
$params = ['admin', 1];
$success = odbc_execute($stmt, $params);
if (!$success) die("Execute 失敗: " . odbc_errormsg($conn));
// 獲取結果
while ($row = odbc_fetch_array($stmt)) {
print_r($row);
}
odbc_free_result($stmt);
<?php
$conn = odbc_connect('MyAppDB', 'sa', 'Passw0rd');
// 關閉自動提交
odbc_autocommit($conn, false);
try {
odbc_exec($conn, "INSERT INTO logs (msg) VALUES ('Step 1')");
odbc_exec($conn, "UPDATE accounts SET balance = balance - 100 WHERE id = 1");
odbc_exec($conn, "UPDATE accounts SET balance = balance + 100 WHERE id = 2");
odbc_exec($conn, "INSERT INTO logs (msg) VALUES ('Step 2')");
// 提交
odbc_commit($conn);
echo "事務提交成功\n";
} catch (Exception $e) {
// 回滾
odbc_rollback($conn);
echo "事務回滾: {$e->getMessage()}\n";
}
// 恢復自動提交
odbc_autocommit($conn, true);
<?php
function odbcQuery($conn, string $sql, array $params = []): array {
if ($params) {
$stmt = odbc_prepare($conn, $sql);
if (!$stmt) throw new Exception("Prepare failed: " . odbc_errormsg($conn));
if (!odbc_execute($stmt, $params)) throw new Exception("Execute failed: " . odbc_errormsg($conn));
} else {
$stmt = odbc_exec($conn, $sql);
if (!$stmt) throw new Exception("Query failed: " . odbc_errormsg($conn));
}
$rows = [];
while ($row = odbc_fetch_array($stmt)) {
$rows[] = $row;
}
odbc_free_result($stmt);
return $rows;
}
// 使用
try {
$users = odbcQuery($conn, "SELECT * FROM users WHERE department = ? AND salary > ?", ['IT', 50000]);
print_r($users);
} catch (Exception $e) {
error_log("ODBC Error: " . $e->getMessage());
}
| 問題 | 原因 | 解決 |
|---|---|---|
| Data source name not found | DSN 名稱錯誤或位數不匹配 | 檢查 32/64 位 ODBC 管理器,PHP 位數必須與驅動一致 |
| Driver not capable | 游標類型不支援 | 連接時加 SQL_CUR_USE_ODBC 強制用戶端游標 |
| Optional feature not implemented | 驅動不支援某功能 (如 scrollable cursor) | 避免使用 odbc_fetch_row($result, $row_num) 定位獲取 |
| 中文亂碼 | 編碼不匹配 | 連接串加 CharacterSet=UTF-8,確保數據庫/表/列編碼一致 |
| 連接慢/超時 | DNS 解析、防火牆、加密協商 | 用 IP 直連、關閉不必要加密、調整 LoginTimeout |
SELECT *odbc_free_result()、odbc_close()sqlsrv/pdo_sqlsrv,MySQL 用 mysqli/pdo_mysql,性能更優ODBC 是異構數據庫互通的通用橋樑。PHP odbc_* 函數提供基礎 CRUD、預處理、事務能力。生產環境注意:DSN 位數匹配、字符集顯式指定、預處理防注入、資源及時釋放。若目標數據庫有原生 PHP 驅動,優先使用原生驅動獲得更好性能與功能支援。