1.文件锁
$file = fopen("list.lock","r");
//LOCK_EX锁定整个文件,LOCK_UN、LOCK_SH锁定文件的一部分,LOCK_NB非阻塞锁
if(!flock($file,LOCK_EX | LOCK_NB)){
return "系统繁忙,请稍后再试";
}
//处理具体业务逻辑
//解除锁定
flock($file,LOCK_UN);
fclose($file );//关闭文件
2.使用消息队列
/**Redis消息队列**/
/**
* @param $key
* @param $goods_id
* @param $num
* @return void 后台开启抢购后启动这一步
*/
function setNum($key='goods_',$goods_id,$num=100)
{
//实例化(实际开发中提出来)
$redis = new Redis();
//连接服务端
$redis->connect('127.0.0.1', 6379);
$res = $redis->set($key.$goods_id,$num);
}
/**
* 秒杀抢购
* @param Request $request
* @return void
*/
function cusBuy(Request $request)
{
//用户、商品信息
$uid = $request->input('uid');
$goods_id = $request->input('goods_id');
//商品库存key
$key = 'goods_'.$goods_id;
//实例化(实际开发中提出来)
$redis = new Redis();
//连接服务端
$redis->connect('127.0.0.1', 6379);
//监听key 监听对应的key,事务提交之前,如果key被修改,则事务被打断
$redis->watch($key);
//检查key uid 是否存在对应已抢购用户ID
if($redis->hGet('uid',$uid)){
return '请误重复抢购';
}
//获取库存
$goods_num = $this->setNum($key);
//开启事务
$redis->multi();
//判断库存是否足够
if($goods_num>0){
$redis->decr($key);//库存减1
//生成订单
$time = time();
$order_no = 'NO'.rand(1000,9999).$time.date('YmdHis',$time);//生成唯一订单
$data = json_encode(['order_no'=>$order_no,'uid'=>$uid]);
//订单信息入队
$redis->rPush("order_no",$data);
//入队成功后当前抢购人员信息放入redis,避免重复抢购
$redis->set('uid',$uid);
//入队后直接返回抢购成功,异步调用入库订单等等
//关闭事务
$redis->exec();
}
}
3.如果是分布式集群的服务器,需要一个或多个队列服务器