php 实现乐观锁实现
乐观锁的基本概念
乐观锁是一种并发控制机制,假设多用户操作不会冲突,只在提交时检测数据是否被修改。适用于读多写少的场景,通常通过版本号或时间戳实现。
实现方式一:基于版本号
在数据表中增加一个version字段,每次更新时检查版本号是否一致。
-- 表结构示例
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
stock INT,
version INT DEFAULT 0
);
// PHP代码示例
$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$id = 1;
$newStock = 10;
// 查询当前版本号和库存
$stmt = $pdo->prepare("SELECT stock, version FROM products WHERE id = ?");
$stmt->execute([$id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
$oldStock = $row['stock'];
$version = $row['version'];
// 更新时检查版本号
$stmt = $pdo->prepare("UPDATE products SET stock = ?, version = version + 1 WHERE id = ? AND version = ?");
$stmt->execute([$newStock, $id, $version]);
if ($stmt->rowCount() === 0) {
echo "更新失败,数据已被其他操作修改";
} else {
echo "更新成功";
}
}
实现方式二:基于时间戳
使用last_updated字段记录最后修改时间,更新时比对时间戳。
-- 表结构示例
ALTER TABLE products ADD COLUMN last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
// PHP代码示例
$stmt = $pdo->prepare("SELECT stock, last_updated FROM products WHERE id = ?");
$stmt->execute([$id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
$oldTimestamp = $row['last_updated'];
// 更新时检查时间戳
$stmt = $pdo->prepare("UPDATE products SET stock = ? WHERE id = ? AND last_updated = ?");
$stmt->execute([$newStock, $id, $oldTimestamp]);
if ($stmt->rowCount() === 0) {
echo "更新失败,数据已被其他操作修改";
}
}
实现方式三:基于条件值
直接比对业务字段(如库存数量),适用于简单场景。

// PHP代码示例
$stmt = $pdo->prepare("UPDATE products SET stock = ? WHERE id = ? AND stock = ?");
$stmt->execute([$newStock, $id, $oldStock]);
if ($stmt->rowCount() === 0) {
echo "更新失败,库存已变化";
}
注意事项
- 重试机制:乐观锁失败后通常需要重试,建议结合循环或队列处理。
- 性能影响:版本号或时间戳需加索引,避免全表扫描。
- 事务隔离:确保操作在事务内执行,避免脏读问题。






