基于Redis的消息队列实现固定库存商品抢购
//商品总库存需要在后台写入到库存队里中,提前写入
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis->auth('alloc');
$redis->select(1);
//获取库存并减一写入队列
$k = $redis->lPop('sale_count');
echo $k;
if($k>1){
if($k-1 == 0){
$redis->del('sale_count');
}else{
$redis->lPush('sale_count',$k-1);
}
echo '抢购成功!';
}else{
echo '售卖完毕!';
}
基于上面的基础解决购买数量存储,超时不支付订单取消订单并恢复库存
<?php
//商品总库存需要在后台写入到库存队里中,提前写入
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('alloc');
$redis->select(1);
//
$user_id = rand(1, 10000);//随机模拟用户ID 不去重复了实际情况下没有重复的
$buy_num = rand(1, 9);//随机模拟购买数量
//获取库存并减一写入队列
$k = $redis->lPop('sale_count');
if ($k > 1) {
if ($k - $buy_num <= 0) {
exit('库存不足');
}else{
$redis->rPush('get_good_list', $user_id);//将抢到顺序插入队列,在守护进程1中处理
$redis->setex($user_id, 1800, $buy_num);//设置超时时间30分钟
$redis->rPush('sale_count', $k - $buy_num);
}
echo '抢购成功!,请五分钟内支付';
} else {
echo '售卖完毕!';
}
<?php
##Daemon1.php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('alloc');
$redis->select(1);
//while (1){
$user_id = $redis->lPop('get_good_list');
if($user_id){
//获取购买数量
$buy_num = $redis->get($user_id);
//创建订单
$order_no = createOder($user_id,$buy_num);
//设置订单超时时间
$redis->setex($order_no,300,1);//5分钟未支付通知Daemon2.php
}
//}
<?php
#Daemon2.php
ini_set('default_socket_timeout', -1); //不超时
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('alloc');
$redis->select(1);
//不超时
$redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
//创建事件监听,__keyevent@1__:expired,数字1代表数据库序号
$redis->psubscribe(array('__keyevent@1__:expired'), 'keyCallback');
// 回调函数,这里写处理逻辑
function keyCallback($redis, $pattern, $chan, $order_no){
//获取订单信息 获取购买数量
$buy_num = getOderInfo($order_no);
//关闭订单
closeOrder();
//加入库存
$redis->rPush('sale_count',$redis->lPop('sale_count')+$buy_num);
}