以下是一个使用乐观锁的简单示例代码,演示如何在PHP中使用Redis进行商品秒杀并防止超卖:
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$productKey = 'product_stock';
$userId = 'user123';
$purchaseQuantity = 1;
// 开始秒杀
if (seckillProduct($productKey, $userId, $purchaseQuantity)) {
echo "秒杀成功!\n";
} else {
echo "秒杀失败,库存不足或已购买过!\n";
}
function seckillProduct($productKey, $userId, $quantity)
{
global $redis;
// 使用 WATCH 监视 product_stock 键
$redis->watch($productKey);
// 获取当前商品库存
$stock = (int)$redis->get($productKey);
// 检查库存是否足够
if ($stock >= $quantity) {
// 开启事务
$redis->multi();
// 减少库存
$redis->decrby($productKey, $quantity);
// 模拟生成订单等其他操作
generateOrder($userId, $quantity);
// 提交事务
$result = $redis->exec();
// 检查事务执行结果
if ($result !== false) {
return true; // 秒杀成功
}
}
// 取消 WATCH,事务未执行
$redis->unwatch();
return false; // 秒杀失败
}
function generateOrder($userId, $quantity)
{
// 此处可以添加生成订单等相关操作的代码,示例中只输出信息
echo "生成订单:用户ID {$userId} 购买数量 {$quantity}\n";
}
在这个示例中,seckillProduct
函数使用了乐观锁的概念。首先,它使用 WATCH
命令监视商品库存键。然后,它检查库存是否足够,如果足够,就开始一个事务,减少库存并执行其他操作(例如生成订单)。最后,使用 EXEC
提交事务,如果提交成功,说明秒杀操作成功,否则说明库存不足或者在监视期间发生了并发操作,需要重试或处理失败。
请注意,这只是一个简单的示例,实际应用中可能需要更复杂的逻辑和错误处理。在高并发环境中,还需要考虑性能和并发控制,可能需要进一步优化和测试。