在多機併發環境下,傳統文件鎖或記憶體鎖無法跨進程、跨伺服器生效。利用 MySQL 唯一索引特性,透過「插入記錄」獲取鎖、「刪除記錄」釋放鎖,是一種輕量且可靠的分佈式鎖方案。本文提供完整 Shell 函數示例,並補充 PHP+MySQL 基礎操作範例。
建議建立專用鎖表 t_trans_lock,包含 dataId(業務標識)、dataDate(日期分片)等欄位,並建立唯一聯合索引:
CREATE TABLE t_trans_lock (
dataId VARCHAR(64) NOT NULL,
dataDate DATE NOT NULL,
PRIMARY KEY (dataId, dataDate)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
InnoDB 引擎支援行級鎖與事務,是實現可靠分佈式鎖的基礎。
原文提供的 Shell 函數邏輯清晰,轉為 PHP 版本更便於整合:
function getLock(PDO $pdo, string $dataId, string $dataDate): bool {
$sql = "INSERT IGNORE INTO t_trans_lock (dataId, dataDate) VALUES (?, ?)";
$stmt = $pdo->prepare($sql);
return $stmt->execute([$dataId, $dataDate]) && $stmt->rowCount() > 0;
}
function freeLock(PDO $pdo, string $dataId, string $dataDate): bool {
$sql = "DELETE FROM t_trans_lock WHERE dataId = ? AND dataDate = ?";
$stmt = $pdo->prepare($sql);
return $stmt->execute([$dataId, $dataDate]);
}
關鍵點:INSERT IGNORE 遇唯一鍵衝突不報錯且不插入,配合 rowCount() 判斷是否搶佔成功;刪除時不強制要求受影響行數,避免業務邏輯異常導致鎖殘留。
雖然原文包含較舊的 mysql_* 函數示例,但現代專案強烈建議使用 PDO 或 mysqli 預處理語句,防止 SQL 注入並支援事務。以下為規範寫法:
// 連接配置
$dsn = 'mysql:host=localhost;dbname=eastses;charset=utf8mb4';
$pdo = new PDO($dsn, 'username', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// 安全插入示例(預處理)
$sql = "INSERT INTO classmate (name, nickname, birthday) VALUES (?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$_POST['name'], $_POST['nickname'], $_POST['birthday']]);
POST 資料,過濾轉義(或用預處理)。password_hash() 加鹽哈希存儲,絕不存明文。基於 MySQL 唯一鍵的分佈式鎖,實現簡單、無額外組件依賴,適合中小型系統的定時任務防重、跨機互斥等場景。生產環境請務必: