連接方式對比
| 特性 | mysqli 程序式 | mysqli 物件導向 (推薦) | PDO (通用) |
| 語法風格 | 函數式 | 類別方法 | 類別方法 |
| 多資料庫支援 | 否 | 否 | 是 |
| 預處理語句 | 支援 | 支援 | 支援 |
| 錯誤處理 | 回傳 false + mysqli_error() | 例外模式可啟用 | 例外模式預設 |
mysqli 物件導向連接 (推薦現代寫法)
<?php
// 設定參數
$host = 'localhost';
$user = 'db_user';
$pass = 'secure_password';
$dbname = 'my_database';
$port = 3306;
$charset = 'utf8mb4';
try {
// 1. 建立連接
$mysqli = new mysqli($host, $user, $pass, $dbname, $port);
// 2. 檢查連接錯誤
if ($mysqli->connect_errno) {
throw new Exception("連接失敗: " . $mysqli->connect_error);
}
// 3. 設定字元集 (重要!防止中文亂碼)
$mysqli->set_charset($charset);
// 4. 啟用例外錯誤模式 (PHP 8.1+ 預設開啟)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
echo "資料庫連接成功!";
// ... 執行查詢操作 ...
} catch (Exception $e) {
error_log("DB Error: " . $e->getMessage());
die("系統暫時無法連接資料庫,請稍後再試");
} finally {
// 5. 關閉連接 (腳本結束會自動關閉,長時間運行腳本建議手動關閉)
if (isset($mysqli)) {
$mysqli->close();
}
}
?>
mysqli 程序式連接 (舊專案相容)
<?php
$host = 'localhost';
$user = 'db_user';
$pass = 'secure_password';
$dbname = 'my_database';
$link = mysqli_connect($host, $user, $pass, $dbname);
if (!$link) {
die('連接失敗: ' . mysqli_connect_error());
}
mysqli_set_charset($link, 'utf8mb4');
// 使用方式:mysqli_query($link, $sql)
// 關閉:mysqli_close($link);
?>
連接參數詳細說明
| 參數 | 說明 | 預設值 |
$host | 主機名或 IP,本機用 localhost 或 127.0.0.1 | localhost:3306 |
$user | 資料庫使用者名稱 | 擁有進程的用戶 |
$pass | 密碼 | 空字串 |
$dbname | 預設資料庫 (可省略,後續用 select_db) | 無 |
$port | 連接埠 | 3306 |
$socket | Unix Socket 路徑 (本機連線可用) | /var/run/mysqld/mysqld.sock |
進階連接選項
<?php
$mysqli = new mysqli();
// 初始化並設定選項
$mysqli->init();
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5); // 連線逾時 5 秒
$mysqli->options(MYSQLI_OPT_READ_TIMEOUT, 30); // 讀取逾時 30 秒
$mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true); // 驗證 SSL 憑證
$mysqli->options(MYSQLI_INIT_COMMAND, "SET NAMES utf8mb4"); // 連線後自動執行
// 真正建立連接
$mysqli->real_connect($host, $user, $pass, $dbname, $port, $socket, MYSQLI_CLIENT_SSL);
if ($mysqli->connect_errno) {
throw new Exception("連接失敗: " . $mysqli->connect_error);
}
?>
持久連接
// 物件導向:主機名加前綴 p:
$mysqli = new mysqli('p:localhost', $user, $pass, $dbname);
// 程序式
$link = mysqli_connect('p:localhost', $user, $pass, $dbname);
注意:持久連接會復用進程間的連接,需注意:
- 連接數易達
max_connections 上限
- 狀態變數(用戶變數、臨時表、預處理語句)會殘留
- PHP-FPM 模式下每個 worker 進程維持連接池
- 建議搭配
mysqli::change_user() 重置狀態
常見錯誤排查
| 錯誤 | 原因 | 解決 |
| Access denied | 帳號/密碼/主機不匹配 | 檢查 mysql.user 表 Host 欄位,FLUSH PRIVILEGES |
| Can't connect to MySQL server | 服務未啟動/端口錯誤/防火牆 | systemctl status mysqld, netstat -tlpn | grep 3306 |
| Class 'mysqli' not found | PHP 未安裝/啟用 mysqli 擴展 | 安裝 php-mysqli, 啟用 extension=mysqli |
| SSL connection error | SSL 憑證驗證失敗 | 設定 MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT 或配置 CA |
最佳實踐清單
- ✅ 使用物件導向
mysqli 或 PDO
- ✅ 啟用
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)
- ✅ 明確設定
utf8mb4 字元集
- ✅ 使用預處理語句防 SQL 注入
- ✅ 長運行腳本手動
close(),Web 請求依賴自動回收
- ✅ 生產環境隱藏錯誤細節,記錄至日誌
- ✅ 連接參數從環境變數/配置檔讀取,不硬編碼