php实现悲观锁
悲观锁的基本概念
悲观锁假设并发冲突频繁发生,因此在操作数据前先加锁,确保其他事务无法修改数据。适用于写多读少的场景,常见实现方式包括数据库行锁或表锁。

通过MySQL实现悲观锁
使用SELECT ... FOR UPDATE语句锁定查询的行,直到事务结束(提交或回滚)后释放锁。需确保在事务中执行:

$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$pdo->beginTransaction();
try {
// 锁定id=1的行
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = 1 FOR UPDATE");
$stmt->execute();
$product = $stmt->fetch(PDO::FETCH_ASSOC);
// 更新操作
$updateStmt = $pdo->prepare("UPDATE products SET stock = stock - 1 WHERE id = 1");
$updateStmt->execute();
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
echo "Error: " . $e->getMessage();
}
使用文件锁(File Lock)
对于非数据库场景,可通过flock函数实现文件系统级别的悲观锁:
$fp = fopen("lockfile.txt", "w+");
if (flock($fp, LOCK_EX)) { // 获取独占锁
// 执行需要加锁的代码
file_put_contents("data.txt", "updated content");
flock($fp, LOCK_UN); // 释放锁
} else {
echo "Could not lock the file!";
}
fclose($fp);
注意事项
- 死锁风险:悲观锁可能导致死锁,需合理设计锁的获取顺序或设置超时时间。
- 性能影响:长时间持有锁会降低系统吞吐量,建议缩小锁的作用范围和持有时间。
- 数据库支持:不同数据库对
FOR UPDATE的实现可能不同,需检查数据库文档(如MySQL的InnoDB引擎支持行锁)。
锁超时处理
MySQL可通过设置锁等待超时(默认50秒),超时后自动回滚:
SET innodb_lock_wait_timeout = 10; -- 设置超时为10秒
PHP代码中可捕获超时异常并重试或提示用户。






