秒杀接口优化
1. 系统初始化,把商品库存数量加载到Redis
MiaoshaController实现InitializingBean
public void afterPropertiesSet() throws Exception {
List goodsList = goodsService.listGoodsVo();
if (goodsList == null) {
return;
}
for (GoodsVo goods : goodsList) { redisService.set(GoodsKey.getMiaoshaGoodsStock, "" + goods.getId(), goods.getStockCount()); localOverMap.put(goods.getId(), false);
}
}
2.收到请求,Redis预减库存,库存不足,直接返回,否则进入3
先判断是否是重复秒杀,然后预减库存,如果库存数量小于0,返回秒杀结束;
否则请求入队
@ResponseBody
public Result miaosha(Model model, MiaoshaUser user, @RequestParam("goodsId") long goodsId) {
model.addAttribute("user", user);
if (user == null) {
return Result.error(CodeMsg.SESSION_ERROR); } // 判断是否重复秒杀
}
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if (order != null) {
return Result.error(CodeMsg.REPEATE_MIAOSHA); } // 内存标记,减少redis访问
}
boolean over = localOverMap.get(goodsId);
if (over) {
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
// 预减库存
long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);// 10
if (stock < 0) {
localOverMap.put(goodsId, true);
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
// 入队
MiaoshaMessage mm = new MiaoshaMessage();
mm.setUser(user);
mm.setGoodsId(goodsId); sender.sendMiaoshaMessage(mm);
return Result.success(0);// 排队中
}
3.请求入队,立即返回排队中
4.请求出队,生成订单,减少库存
出队后,先判断商品库存是否小于等于0,是否是重复订单,调用miaoshaService.miaosha(user, goods);//减库存,下订单
@Transactional public OrderInfo miaosha(MiaoshaUser user, GoodsVo goods) {
//减库存 下订单 写入秒杀订单
boolean success = goodsService.reduceStock(goods);
if(success) { //order_info maiosha_order
return orderService.createOrder(user, goods); }
else {
setGoodsOver(goods.getId());
return null;
}
}
setGoodsOver就是用redis标记该商品已经卖完了。
OrderService.createOrder(MiaoshaUser user, GoodsVo goods)
OrderInfo orderInfo = new OrderInfo();
...
orderDao.insert(orderInfo);
MiaoshaOrder miaoshaOrder = new MiaoshaOrder(); miaoshaOrder.setGoodsId(goods.getId()); miaoshaOrder.setOrderId(orderInfo.getId()); miaoshaOrder.setUserId(user.getId()); orderDao.insertMiaoshaOrder(miaoshaOrder);
redisService.set(OrderKey.getMiaoshaOrderByUidGid, ""+user.getId()+"_"+goods.getId(), miaoshaOrder);
//最后将哪个用户买了哪件商品放入redis,用于以后判断是否为重复秒杀
5.客户端轮询,是否秒杀成功。
接口的定义:
/**
* orderId:成功
-1:秒杀失败
0: 排队中
*/
@RequestMapping(value = "/result", method = RequestMethod.GET)
@ResponseBody
网友评论