棄用古老 mysql_* 函數(PHP 7.0 移除),採用 mysqli 面向對象 或 PDO,配合預處理語句、事務、連接池,構建安全高效數據層。
// 1. 連接
$mysqli = new mysqli('localhost', 'root', 'pass', 'test', 3306);
if ($mysqli->connect_errno) {
die("Connect failed: " . $mysqli->connect_error);
}
// 2. 設置字符集(關鍵!防亂碼)
$mysqli->set_charset('utf8mb4');
// 3. 預處理語句(防注入、性能優)
$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 = '2024-01-01';
$stmt->execute();
// 4. 綁定結果
$stmt->bind_result($id, $name, $email);
while ($stmt->fetch()) {
echo "ID: $id, Name: $name, Email: $email\n";
}
$stmt->close();
// 5. 事務控制
$mysqli->begin_transaction();
try {
$stmt = $mysqli->prepare("INSERT INTO orders (user_id, amount) VALUES (?, ?)");
$stmt->bind_param('id', $uid, $amt);
foreach ($orders as $o) {
$uid = $o['uid']; $amt = $o['amt'];
$stmt->execute();
}
$stmt->close();
$mysqli->commit();
} catch (Exception $e) {
$mysqli->rollback();
throw $e;
}
// 6. 關閉連接
$mysqli->close();
| 實踐 | 代碼/配置 | 理由 |
|---|---|---|
| 預處理語句 | $stmt->bind_param() | 防 SQL 注入、預編譯緩存、類型安全 |
| 顯式字符集 | $mysqli->set_charset('utf8mb4') | 避免亂碼、支持 Emoji |
| 錯誤模式異常 | $mysqli->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT | 自動拋出異常,無需手動檢查 errno |
| 事務原子性 | begin_transaction()/commit()/rollback() | 保證數據一致性 |
| 批量操作 | multi_query() 或 循環 execute() | 減少網絡往返 |
| 獲取自增 ID | $mysqli->insert_id | INSERT 後立即獲取 |
PHP-FPM 多進程模式下,每進程維護連接池。推薦方案:
Swoole\Coroutine\MySQL 連接池,高併發首選mysqli::real_connect 持久連接 p: 前綴(慎用,易洩漏)// Swoole 協程連接池示例
$pool = new Swoole\Coroutine\MySQL\Pool(
(object)[
'host' => '127.0.0.1', 'port' => 3306,
'user' => 'root', 'password' => 'pass', 'database' => 'test',
'charset' => 'utf8mb4'
],
20 // 最大連接數
);
go(function () use ($pool) {
$db = $pool->get();
$result = $db->query("SELECT * FROM users LIMIT 10");
$pool->put($db);
});
$pdo = new PDO(
'mysql:host=localhost;dbname=test;charset=utf8mb4',
'root', 'pass',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 真實預處理
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$user = $stmt->fetch();
max_prepared_stmt_count 限制現代 PHP 專案建議:Hyperf/Laravel/Symfony 框架內置 DBAL/ORM,底層封裝 PDO/mysqli,提供查詢構建器、遷移、種子、模型關聯,專注業務邏輯而非 SQL 拼接。