PHP 為 Session 儲存提供了三種核心機制:檔案儲存(預設)、記憶體儲存以及自定義儲存。預設的檔案儲存雖然簡單易用,但在高流量網站中會產生大量 I/O 操作,嚴重影響效能。本文將詳細介紹如何實作基於 MySQL 的自定義 Session 儲存方案,有效解決高併發場景下的效能瓶頸。
首先建立專門儲存 Session 資料的資料表,結構簡潔明確:
CREATE TABLE mysession (
session_key CHAR(32) NOT NULL,
session_data TEXT,
session_expiry INT(11),
PRIMARY KEY (session_key)
);
透過實作六個回調函數並註冊給 session_set_save_handler(),即可接管 Session 的完整生命週期:
function mysession_open($save_path, $session_name) {
$link = @mysqli_connect("localhost", "root", "root", "php");
if (!$link) die("資料庫連線失敗");
$_SESSION['mysqli_link'] = $link; // 儲存連線供後續使用
return true;
}
function mysession_close() {
if (isset($_SESSION['mysqli_link'])) {
mysqli_close($_SESSION['mysqli_link']);
}
return true;
}
function mysession_read($key) {
$link = $_SESSION['mysqli_link'] ?? mysqli_connect("localhost", "root", "root", "php");
$expiry_time = time();
$key = mysqli_real_escape_string($link, $key);
$query = "SELECT session_data FROM mysession
WHERE session_key = '$key' AND session_expiry > $expiry_time";
$result = mysqli_query($link, $query);
if ($row = mysqli_fetch_assoc($result)) {
return $row['session_data'];
}
return '';
}
function mysession_write($key, $data) {
$link = $_SESSION['mysqli_link'] ?? mysqli_connect("localhost", "root", "root", "php");
$expiry_time = time() + 1200; // 20 分鐘有效期
$key = mysqli_real_escape_string($link, $key);
$data = mysqli_real_escape_string($link, $data);
// 使用 INSERT ... ON DUPLICATE KEY UPDATE 原子操作
$query = "INSERT INTO mysession (session_key, session_data, session_expiry)
VALUES ('$key', '$data', $expiry_time)
ON DUPLICATE KEY UPDATE
session_data = '$data', session_expiry = $expiry_time";
return mysqli_query($link, $query);
}
function mysession_destroy($key) {
$link = $_SESSION['mysqli_link'] ?? mysqli_connect("localhost", "root", "root", "php");
$key = mysqli_real_escape_string($link, $key);
$query = "DELETE FROM mysession WHERE session_key = '$key'";
return mysqli_query($link, $query);
}
function mysession_gc($maxlifetime) {
$link = $_SESSION['mysqli_link'] ?? mysqli_connect("localhost", "root", "root", "php");
$expiry_time = time();
$query = "DELETE FROM mysession WHERE session_expiry < $expiry_time";
return mysqli_query($link, $query);
}
session_set_save_handler(
'mysession_open',
'mysession_close',
'mysession_read',
'mysession_write',
'mysession_destroy',
'mysession_gc'
);
// 必須在 session_start() 之前註冊
session_start();
<?php
require_once 'session_handler.php'; // 包含上述處理器定義
session_start();
$_SESSION['username'] = 'Simon';
$_SESSION['password'] = '123456';
echo "Session 已儲存至資料庫";
?>
<?php
require_once 'session_handler.php';
session_start();
echo "UserName: " . $_SESSION['username'] . "<br>";
echo "PassWord: " . $_SESSION['password'] . "<br>";
?>
錯誤:
Failed to initialize storage module原因: Session 啟動時資料庫連線尚未就緒(如資料庫服務延遲啟動)。
解決: 確保資料庫服務優於 Web 伺服器啟動,或在處理器中加入重試機制。