php实现乐观锁
乐观锁的概念
乐观锁是一种并发控制机制,假设多用户并发操作不会产生冲突,只在提交数据时检查是否有冲突。适用于读多写少的场景。
基于版本号的实现
在数据表中增加一个version字段,每次更新时检查版本号是否一致。

// 假设$pdo是已建立的PDO连接
$id = 1;
$newValue = '更新后的值';
// 开启事务
$pdo->beginTransaction();
try {
// 查询当前数据和版本号
$stmt = $pdo->prepare("SELECT value, version FROM table WHERE id = ?");
$stmt->execute([$id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$currentVersion = $row['version'];
// 更新数据,同时检查版本号
$updateStmt = $pdo->prepare(
"UPDATE table SET value = ?, version = version + 1
WHERE id = ? AND version = ?"
);
$updateStmt->execute([$newValue, $id, $currentVersion]);
// 检查是否更新成功
if ($updateStmt->rowCount() === 0) {
throw new Exception("数据已被其他进程修改,请重试");
}
// 提交事务
$pdo->commit();
echo "更新成功";
} catch (Exception $e) {
$pdo->rollBack();
echo "错误: " . $e->getMessage();
}
基于时间戳的实现
使用时间戳字段替代版本号,原理类似但精度更高。
$id = 1;
$newValue = '更新后的值';
$currentTimestamp = time(); // 或从数据库获取
$updateStmt = $pdo->prepare(
"UPDATE table SET value = ?, last_modified = ?
WHERE id = ? AND last_modified = ?"
);
$updateStmt->execute([
$newValue,
$currentTimestamp,
$id,
$row['last_modified']
]);
CAS(Compare-And-Swap)实现
直接比较原值是否变化,适合简单场景。

$id = 1;
$newValue = '新值';
$oldValue = '原值';
$updateStmt = $pdo->prepare(
"UPDATE table SET value = ? WHERE id = ? AND value = ?"
);
$updateStmt->execute([$newValue, $id, $oldValue]);
if ($updateStmt->rowCount() === 0) {
echo "数据已被修改,操作失败";
}
重试机制
乐观锁冲突时应实现重试逻辑。
$maxRetries = 3;
$retryCount = 0;
while ($retryCount < $maxRetries) {
try {
// 尝试更新操作
if (updateWithOptimisticLock()) {
break;
}
} catch (Exception $e) {
$retryCount++;
if ($retryCount >= $maxRetries) {
throw $e;
}
usleep(100000); // 等待100ms后重试
}
}
框架集成示例
Laravel中使用乐观锁:
// 模型需包含version字段
$article = Article::find(1);
// 修改数据
$article->title = '新标题';
try {
$article->save(); // Laravel会自动处理版本冲突
} catch (\Illuminate\Database\StaleModelLockException $e) {
// 处理冲突
}
注意事项
- 乐观锁不解决ABA问题(值被改回原值)
- 高并发写场景可能产生大量重试
- 需合理设置重试次数和间隔
- 事务范围应尽可能小以减少冲突






