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

PHP 連接 MySQL 完整指南:核心函數詳解、最佳實踐與避坑清單

     編輯:PHP 綜合知識

MySQL 憑藉輕量、跨平台、多線程、開源等特性,成為 PHP Web 開發首選數據庫。雖然現代框架多封裝 PDO/Eloquent,但掌握原生 mysql_* / mysqli_* 函數對維護舊專案、理解底層行為、排查疑難雜症至關重要。本文系統整理核心 API、連接模式、錯誤處理與安全規範。

核心 API 速查表(mysqli 面向過程風格)

| 函數 | 用途 | 關鍵參數 | 返回值 | 常見陷阱 | |------|------|----------|--------|----------| | mysqli_connect() | 建立連接 | host, user, pass, db, port, socket | 連接對象 / false | 預設端口 3306,長連接用 mysqli_pconnect() | | mysqli_select_db() | 選擇默認數據庫 | link, db_name | bool | 連接時可直接指定 db 參數省略此步 | | mysqli_query() | 執行 SQL | link, query, mode | 結果集對象 / bool | SELECT 返回結果集,DML 返回 bool,**需嚴格檢查 false** | | mysqli_fetch_assoc() | 取關聯陣列 | result | 陣列 / false | 僅移動指針一行,配合 while 迴圈遍歷 | | mysqli_fetch_row() | 取索引陣列 | result | 陣列 / false | 性能略優於 assoc,但可讀性差 | | mysqli_fetch_array() | 取混合陣列 | result, mode | 陣列 / false | MYSQLI_BOTH 佔用雙倍內存,大結果集慎用 | | mysqli_num_rows() | 獲取行數 | result | int | 僅緩衝查詢有效,非緩衝需先 mysqli_store_result() | | mysqli_num_fields() | 獲取列數 | result | int | 配合 mysqli_fetch_field() 獲取元數據 | | mysqli_free_result() | 釋放結果集 | result | void | **長腳本必須顯式調用**,防止內存洩漏 | | mysqli_close() | 關閉連接 | link | void | 非持久連接腳本結束自動關閉,持久連接需手動管理 | | mysqli_error() | 獲取錯誤信息 | link | string | **生產環境禁用直接輸出**,記錄日誌並返回友好提示 | | mysqli_errno() | 獲取錯誤代碼 | link | int | 1062(重複鍵)、1452(外鍵失敗) 等常見代碼需熟記 |

連接模式深度解析

1. 短連接(預設)

$link = mysqli_connect('127.0.0.1', 'user', 'pass', 'db', 3306);
if (!$link) die('連接失敗: ' . mysqli_connect_error());
// 業務邏輯...
mysqli_close($link);

✅ 簡單、無狀態、適合低併發、PHP-FPM 模式下自動回收。

2. 持久連接 (mysqli_pconnect)

$link = mysqli_pconnect('127.0.0.1', 'user', 'pass', 'db');
// 進程池複用連接,不自動關閉

⚠️ 風險:連接數易達 max_connections 上限;事務狀態殘留導致髒讀;長查詢阻塞整個進程池。**高併發 Web 環境強烈不建議使用**,改用連接池中間件(ProxySQL、MaxScale)。

完整 CRUD 範例(預處理語句版——生產標準)

<?php
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
if ($mysqli->connect_errno) {
    error_log("DB Connect Failed: {$mysqli->connect_error}");
    exit('服務暫時不可用');
}
$mysqli->set_charset('utf8mb4'); // 關鍵:防注入、支援 Emoji

// 1. Prepared Statement 查詢
$stmt = $mysqli->prepare("SELECT id, name, email FROM users WHERE status = ? AND created_at > ?");
$stmt->bind_param('is', $status, $date); // i=integer, s=string, d=double, b=blob
$status = 1;
$date   = '2023-01-01';
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
    echo "{$row['name']} <{$row['email']}>\n";
}
$stmt->close();

// 2. 事務處理
$mysqli->begin_transaction();
try {
    $stmt = $mysqli->prepare("INSERT INTO orders (user_id, total) VALUES (?, ?)");
    $stmt->bind_param('id', $uid, $total);
    $stmt->execute();
    $order_id = $mysqli->insert_id;

    $stmt = $mysqli->prepare("INSERT INTO order_items (order_id, product_id, qty) VALUES (?, ?, ?)");
    $stmt->bind_param('iii', $order_id, $pid, $qty);
    foreach ($items as $item) {
        $pid = $item['pid']; $qty = $item['qty'];
        $stmt->execute();
    }
    $mysqli->commit();
} catch (Exception $e) {
    $mysqli->rollback();
    error_log("Order Failed: {$e->getMessage()}");
}
$mysqli->close();
?>

避坑清單(血淚總結)

  1. 字符集未設定:必須 SET NAMES utf8mb4 或 $mysqli->set_charset('utf8mb4'),否則 GBK 雙字節注入、Emoji 存儲失敗。
  2. 錯誤信息輸出到頁面:洩露表結構、路徑、用戶名。生產環境 display_errors=Off,統一記錄 error_log。
  3. 未檢查查詢返回值:if (!$result) { log_error($mysqli->error); return false; } 每次查詢必加。
  4. 大結果集未分頁/流式處理:SELECT * FROM huge_table 直接 OOM。使用 LIMIT 分頁或 mysqli_use_result() 非緩衝模式逐行處理。
  5. SQL 拼接變量:嚴禁 "WHERE name = '$name'",**永遠使用預處理綁定參數**。
  6. 連接未釋放:長運行腳本(爬蟲、導入)必須顯式 mysqli_free_result()、mysqli_close()。
  7. 權限過大:應用賬號僅授 SELECT,INSERT,UPDATE,DELETE,**無 DDL、GRANT、FILE 權限**。

從 mysql_* 遷移到 mysqli/PDO 路徑圖

  • PHP 5.5 棄用 mysql_*,PHP 7.0 移除。存量專案優先改用 mysqli 面向過程風格(語法最接近),再逐步重構為面向對象/PDO。
  • 自動化工具:phpstan + php-cs-fixer 規則集可批量檢測/修復舊 API 調用。
  • 新專案**直接使用 PDO**——統一多數據庫介面、支援命名參數、異常模式更符合現代習慣。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved