php乐观锁实现
乐观锁的实现原理
乐观锁是一种并发控制机制,假设多用户并发操作时不会冲突,只在提交时检测数据是否被修改。通常通过版本号(version)或时间戳(timestamp)实现。
基于版本号的实现
-
数据表设计
在表中添加一个version字段,类型为整型或时间戳:ALTER TABLE `products` ADD COLUMN `version` INT DEFAULT 0; -
更新时检查版本
执行更新操作时,在WHERE条件中加入版本检查,并递增版本号:$pdo->beginTransaction(); $productId = 1; $currentVersion = $pdo->query("SELECT version FROM products WHERE id = $productId")->fetchColumn(); // 业务逻辑处理... $stmt = $pdo->prepare("UPDATE products SET stock = stock - 1, version = version + 1 WHERE id = ? AND version = ?"); $affectedRows = $stmt->execute([$productId, $currentVersion]); if ($affectedRows === 0) { $pdo->rollBack(); throw new Exception("并发修改冲突"); } $pdo->commit();
基于时间戳的实现
-
数据表设计
使用updated_at字段记录最后修改时间:ALTER TABLE `orders` ADD COLUMN `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; -
更新时比对时间戳
在更新时验证时间戳是否变化:$lastUpdated = $pdo->query("SELECT updated_at FROM orders WHERE id = 123")->fetchColumn(); // 处理业务逻辑... $result = $pdo->exec("UPDATE orders SET status = 'paid' WHERE id = 123 AND updated_at = '$lastUpdated'"); if ($result === 0) { throw new Exception("数据已被其他进程修改"); }
使用CAS(Compare-And-Swap)操作
适用于Redis等内存数据库,通过原子性命令实现:
$redis = new Redis();
$redis->connect('127.0.0.1');
$key = 'product:1001';
$currentValue = $redis->get($key);
// 业务计算...
$newValue = $currentValue - 1;
// 仅当值未变化时更新
$success = $redis->watch($key);
if ($success) {
$redis->multi()
->set($key, $newValue)
->exec();
}
注意事项
- 乐观锁适用于冲突频率低的场景,高频冲突建议改用悲观锁
- 需配合事务使用确保原子性
- 前端可配合显示版本号,避免提交过期数据







