今天我们说的是要实现一个用户只能抢购一件商品
首先我们来了解一下blpop
BLPOP 是列表的阻塞式(blocking)弹出原语。
它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素
非阻塞行为
当 BLPOP 被调用时,如果给定 key 内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字一起,组成结果返回给调用者
阻塞行为
如果所有给定 key 都不存在或包含空列表,那么 BLPOP 命令将阻塞连接,直到等待超时,或有另一个客户端对给定 key 的任意一个执行 LPUSH 或 RPUSH 命令为止。
超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely)
相同的key被多个客户端同时阻塞
相同的 key 可以被多个客户端同时阻塞。
不同的客户端被放进一个队列中,按『先阻塞先服务』(first-BLPOP,first-served)的顺序为 key 执行 BLPOP 命令
在MULTI/EXEC事务中的BLPOP
BLPOP 可以用于流水线(pipline,批量地发送多个命令并读入多个回复),但把它用在 MULTI / EXEC 块当中没有意义。因为这要求整个服务器被阻塞以保证块执行时的原子性,该行为阻止了其他客户端执行 LPUSH 或 RPUSH 命令。
因此,一个被包裹在 MULTI / EXEC 块内的 BLPOP 命令,行为表现得就像 LPOP 一样,对空列表返回 nil ,对非空列表弹出列表元素,不进行任何阻塞操作
说到这里大家应该对redis blpop有一定的了解了、下面贴出我的代码
public function buyAction() {
$user_id = $_GET['user_id'];
$key = "goods_list:";
$user_key = "user_list:";
$result = $this->redis->blPop($key, 1); // 如果为空 等待1s 超时退出或者发现有弹出元素为止
if (!$result) {
echo "抢购失败";
die;
} else {
//判断是否已经抢购成功了
$user = $this->redis->lRange($user_key, 0, -1);
if (!empty($user) && in_array($user_id, $user)) {
// 如果已经抢购则把库存重新塞进去
$this->redis->lPush($key, 1);
echo "您已抢购成功";
die;
} else {
// 抢购成功,把用户id 存起来
$user = $this->redis->lPush($user_key, $user_id);
echo "抢购成功";
die;
}
}
}