秒杀 预约活动项目中如何高效的保证下单交易成功?保证redis

预约活动(秒杀)项目中如何高效的保证下单交易成功?保证redis,mysql的最终一致性?
前言
`在秒杀项目中,秒杀下单的过程中都需要经历四步,分别为:
1.校验下单状态,商品是否存在,用户是否合法,购买数量是否正确
2.落单减库存,支付减库存
3.订单入库
4.返回前端
这个也就是秒杀项目中的优化核心 。下面来讲解是如何进行秒杀过程优化的 。
参考工程连接地址:
提示:以下是本篇文章正文内容,下面案例可供参考
一、redis引入 1.redis实现对用户账户缓存和商品缓存
可以看到最开始的项目,没有redis的引入,是需要进行多次查询数据库操作 。
可以看到在校验环节查询了三次表一次Item表,一次表,一次promo活动信息表 。
第二扣库存环节扣减了stock表的库存 。所以需要操作两次stock表一次查询一次 。
第三订单入库相当于插入order表这么一次mysql操作 。
一共6次操作 。
代码
//订单创建@PostMapping(value = "http://www.kingceram.com/order/createOrder", consumes = {CONTENT_TYPE_FORMED})public CommonReturnType createItem(@RequestParam(name = "itemId")Integer itemId,@RequestParam(name = "amount")Integer amount,@RequestParam(name = "promoId",required = false)Integer promoId) throws BusinessException {//判断是否登录Boolean isLogin = (Boolean) httpServletRequest.getSession().getAttribute("IS_LOGIN");if(isLogin == null || !isLogin){throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "请登录后再进行预约");}//获取用户的登录信息UserModel userModel = (UserModel) httpServletRequest.getSession().getAttribute("LOGIN_USER");if(redisTemplate.hasKey("promo_item_stock_invalid_"+itemId)){throw new BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);}OrderModel orderModel = orderService.createOrder(userModel.getId(), itemId, promoId, amount);return CommonReturnType.create(null);}
//promoId非空表示已预约活动价格下单(也就是秒杀商品Id)public OrderModel createOrder(Integer userId, Integer itemId, Integer promoId, Integer amount) throws BusinessException {//1.校验下单状态,商品是否存在,用户是否合法,购买数量是否正确ItemModel itemModel = itemService.getItemById(itemId);if (itemModel == null) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "商品信息不存在");}UserModel userModel = userService.getUserById(userId);if (userModel == null) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "用户信息不存在");}if (amount <= 0 || amount > 99) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "数量信息不正确");}//校验活动信息if (promoId != null) {//校验对应活动是否存在这个适用商品if (!promoId.equals(itemModel.getPromoModel().getId())) {throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "活动信息不正确");} else if (itemModel.getPromoModel().getStatus() != 2) {//活动是否正在进行中throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "活动还未开始");}}//2.落单减库存,支付减库存boolean result = itemService.decreaseStock(itemId, amount);if (!result) {throw new BusinessException(EmBusinessError.STOCK_NOT_ENOUGH);}//3.订单入库OrderModel orderModel = new OrderModel();orderModel.setItemId(itemId);orderModel.setUserId(userId);orderModel.setAmount(amount);orderModel.setItemPrice(itemModel.getPrice());//orderModel.setOrderPrice(itemModel.getPrice().multiply(new BigDecimal(amount)));//orderModel.setOrderPrice(itemModel.getPrice().multiply(new BigDecimal(amount)));if (promoId != null) {//商品价格取特价orderModel.setItemPrice(itemModel.getPromoModel().getPromoItemPrice());} else {orderModel.setItemPrice(itemModel.getPrice());}orderModel.setPromoId(promoId);orderModel.setOrderPrice(orderModel.getItemPrice().multiply(new BigDecimal(amount)));//生成交易流水号orderModel.setId(generateOrderNo());OrderDO orderDO = convertFromOrderModel(orderModel);orderDOMapper.insertSelective(orderDO);//加上商品的销量itemService.increaseSales(itemId, amount);//4.返回前端return orderModel;}