PHP+redis实现秒杀,解决并发问题
浏览量:494
秒杀商品添加信息,生成配置文件,并保存好数据
/** * 新增 * @param $goodsid * @return bool|string * author : lianghuiju@chuchujie.com * function_name : insertRedisSeckillActivity * description : */ public function insertRedisSeckillActivity($goodsid,$data) { $this->load->driver('cache'); $resinfo = $data; if ($resinfo) { $key = "seckill_goodsinfo_{$goodsid}";//详情信息 $keyid = "seckill:goodsall:id";//秒杀商品 $key_group = "seckill_group_{$goodsid}";//成团数 $time_diff = ($resinfo['end_time'] - time()) + 1800; $detailgoods = $this->cache->redis->save($key, json_encode($resinfo), $time_diff);//秒杀商品的详细信息 for ($i = 1; $i <= $resinfo['group_num']; $i++) {//成团数 $this->cache->redis->LPUSH($key_group, 1); } $this->cache->redis->EXPIRE($key_group, $time_diff);//设置过期时间 $resllen = $this->cache->redis->llen($key_group); $keyidres = $this->cache->redis->zadd($keyid, 1, $resinfo['goods_id']); if ($resllen == $resinfo['group_num'] && $keyidres >= 0 && $detailgoods) { return true; } else { return false; } } } /** * 更新redis * author : lianghuiju@chuchujie.com * function_name : updateRedisSeckillActivity * description : */ public function updateRedisSeckillActivity($goodsid,$data) { $this->load->driver('cache'); $resinfo = $data; $key = "seckill_goodsinfo_{$goodsid}";//详情信息 $keyid = "seckill:goodsall:id";//秒杀商品 $key_group = "seckill_group_{$goodsid}";//成团数 if ($resinfo) { $time_diff = ($resinfo['end_time'] - time()) + 1800; $detailgoods = $this->cache->redis->save($key, json_encode($resinfo), $time_diff);//秒杀商品的详细信息 $this->cache->redis->del($key_group); for ($i = 1; $i <= $resinfo['group_num']; $i++) {//成团数 $this->cache->redis->LPUSH($key_group, 1); } $this->cache->redis->EXPIRE($key_group, $time_diff);//设置过期时间 $resllen = $this->cache->redis->llen($key_group); $keyidres = $this->cache->redis->zadd($keyid, 1, $resinfo['goods_id']); if ($resllen == $resinfo['group_num'] && $keyidres >= 0 && $detailgoods) { return true; } else { return false; } } } /** * @param $goodsid * @return mixed * author : lianghuiju@chuchujie.com * function_name : deleteRedisSeckillActivity * description : */ public function deleteRedisSeckillActivity($id) { $this->load->driver('cache'); $where = array('id' => $id); $resinfo = $this->getOneSeckillActivity($where); $goodsid = $resinfo['goods_id']; $key = "seckill_goodsinfo_$goodsid";//详情信息 $key_group = "seckill_group_$goodsid";//成团数 $keyid = "seckill:goodsall:id";//秒杀商品 $resid = $this->cache->redis->zrem($keyid, $goodsid); $res = $this->cache->redis->del($key); $resgroup = $this->cache->redis->del($key_group); if ($res >= 0 && $resgroup >= 0 && $resid >= 0) { return true; } else { return false; } }
2.下单区分是秒杀还是普通商品
//TODO 判断普通商品秒杀商品 $this->load->driver('cache'); $key = "seckill:goodsall:id"; $seckill_goodsall = $this->cache->redis->Zrange($key, 0, -1); $goodsid = $this->order_data[0]->items[0]->product_id; if (in_array($goodsid, $seckill_goodsall)) {//秒杀商品 $this->skillMakeOrder(); return; }
3.下单解决并发问题,因为是拼团,所以有团长和团员区分
if (empty($shop['item']->team_sign) && $shop['item']->buy_type == OT_TEAM) { $team_sign = substr(md5($order_sn), 8, 16); $team_first = 1; //如果是团长 不做任何判断 生成团员队列 $key = "seckill_goodsinfo_{$shop['item']->product_id}"; $res = json_decode($this->cache->redis->get($key), true); $key_peoplenum = "seckill_peoplenum_{$shop['item']->product_id}_{$team_sign}"; $time = $res['end_time'] - $res['start_time']; for ($i = 1; $i < $res['group_peoplenum']; $i++) {//团人数 $this->cache->redis->LPUSH($key_peoplenum, 1); } $this->cache->redis->EXPIRE($key_peoplenum, $time);//设置过期时间 } else { $team_sign = $shop['item']->team_sign; $key_group = "seckill_group_{$shop['item']->product_id}";//团数 $key_peoplenum = "seckill_peoplenum_{$shop['item']->product_id}_{$team_sign}";//团人数 $team_first = 2; //如果是团员 团人数减去1 $res = $this->cache->redis->multi()->RPOP($key_peoplenum)->LLEN($key_peoplenum)->exec(); log_message("LOG", "CommoditySeckillPeoplenum Exception: {$key_peoplenum}_{$res[0]}_{$res[1]}"); //TODO $res[0] 代表RPOP if ($res[0] != 1) { throw new Exception('此团人数已满', self::ERROR_TEAM_NUM); } //TODO $res[1] 代表LLEN if ($res[1] == 0) {//组团成功 //记录组团成功 $keyid = "teamsign_success_group_{$shop['item']->product_id}"; $this->cache->redis->zadd($keyid, 1,$team_sign); $group = $this->cache->redis->multi()->RPOP($key_group)->LLEN($key_group)->exec(); log_message("LOG", "CommoditySeckillgroup Exception: {$key_group}_{$res[0]}_{$res[1]}"); if ($group[0] == false) { $group = $this->cache->redis->multi()->RPOP($key_group)->LLEN($key_group)->exec(); } //TODO $group[0] 代表RPOP减失败或者获取失败 if ($group[0] != 1) { throw new Exception('请重试……', self::ERROR_REDIS); } //TODO $group[1] 代表LLEN 组团成功 商品下架 if ($group[1] == 0) { $is_xiajia = true; } } }
最后:简单的几行代码就能控制住并发量,是不是很简单,只要你考虑到redis的原子自增和自减,就可以实现这个问题。里面省略了很多细节。希望你也能完成,加油
神回复
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。