php实现各种锁
PHP 实现文件锁
文件锁通过 flock() 函数实现,适用于单机环境。flock() 提供共享锁(LOCK_SH)和独占锁(LOCK_EX)。
$fp = fopen("lockfile.lock", "w+");
if (flock($fp, LOCK_EX)) { // 独占锁
// 临界区代码
flock($fp, LOCK_UN); // 释放锁
} else {
echo "获取锁失败";
}
fclose($fp);
PHP 实现数据库锁
MySQL 提供行级锁和表级锁。使用 SELECT ... FOR UPDATE 实现悲观锁,事务提交后自动释放。
$pdo->beginTransaction();
$stmt = $pdo->prepare("SELECT * FROM orders WHERE id = ? FOR UPDATE");
$stmt->execute([$orderId]);
// 处理数据
$pdo->commit(); // 释放锁
乐观锁通过版本号或时间戳实现:
UPDATE products SET stock = stock - 1, version = version + 1
WHERE id = ? AND version = ?;
PHP 实现 Redis 锁
使用 Redis 的 SETNX 命令实现分布式锁,配合过期时间防止死锁。
$redis = new Redis();
$redis->connect('127.0.0.1');
$lockKey = 'resource_lock';
$randomValue = uniqid();
$expireTime = 10; // 秒
// 尝试获取锁
if ($redis->set($lockKey, $randomValue, ['NX', 'EX' => $expireTime])) {
try {
// 临界区代码
} finally {
// Lua脚本保证原子性释放
$script = 'if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end';
$redis->eval($script, [$lockKey, $randomValue], 1);
}
}
PHP 实现信号量锁
sem_* 系列函数提供 System V 信号量支持,适用于多进程同步。
$semKey = ftok(__FILE__, 't');
$semId = sem_get($semKey);
if (sem_acquire($semId)) {
// 临界区代码
sem_release($semId);
}
PHP 实现 APC/APCu 锁
APCu 提供原子操作函数,适合单机多进程环境。
if (apcu_add('lock_key', 1, 10)) { // 10秒过期
try {
// 临界区代码
} finally {
apcu_delete('lock_key');
}
}
锁的选择建议
- 单机多线程/进程:文件锁或信号量
- 单机高并发:Redis 锁或 APCu 锁
- 分布式系统:Redis 锁或数据库锁
- 长时间操作:数据库乐观锁
- 短时间高频操作:Redis 原子操作
所有锁实现都应注意设置超时时间,避免死锁情况发生。分布式环境下推荐使用 Redlock 算法等成熟方案。







