上期回顾: Java Seckill Module:Seckill interface front and rear end separation

一、订单详情页面静态化

获取订单详情:页面传入orderId,传入成功则开始渲染页面。

function render(detail){var goods = detail.goods;var order = detail.order;$("#goodsName").text(goods.goodsName);$("#goodsImg").attr("src", goods.goodsImg);$("#orderPrice").text(order.goodsPrice);$("#createDate").text(new Date(order.createDate).format("yyyy-MM-dd hh:mm:ss"));var status = "";if(order.status == 0){status = "未支付"}else if(order.status == 1){status = "待发货";}$("#orderStatus").text(status);}$(function(){getOrderDetail();
})function getOrderDetail(){var orderId = g_getQueryString("orderId");$.ajax({url:"/order/detail",type:"GET",data:{orderId:orderId},success:function(data){if(data.code == 0){render(data.data);}else{layer.msg(data.msg);}},error:function(){layer.msg("客户端请求有误");}});
}

详情接口:

setter、getter省略:

public class OrderDetailVo {private GoodsVo goods;private OrderInfo order;
}

根据orderId查询:

@RequestMapping("/detail")
@ResponseBody
public Result<OrderDetailVo> info(Model model,MiaoshaUser user,
@RequestParam("orderId") long orderId) {if(user == null) {return Result.error(CodeMsg.SESSION_ERROR);}OrderInfo order = orderService.getOrderById(orderId);if(order == null) {return Result.error(CodeMsg.ORDER_NOT_EXIST);}long goodsId = order.getGoodsId();GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);OrderDetailVo vo = new OrderDetailVo();vo.setOrder(order);vo.setGoods(goods);return Result.success(vo);
}
@Select("select * from order_info where id = #{orderId}")
public OrderInfo getOrderById(@Param("orderId")long orderId);
@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.miaosha_price from miaosha_goods mg left join goods g on mg.goods_id = g.id where g.id = #{goodsId}")
public GoodsVo getGoodsVoByGoodsId(@Param("goodsId")long goodsId);

解读:首先查询并获取订单,从订单获取商品id,接着就将商品以及订单写入订单详情里。

到此订单详情静态化就做好了。


二、解决卖超这个问题:

秒杀的步骤:1、判断库存。2、判断是否秒杀了。3、减库存下订单写入秒杀订单。

卖超: 单线程的时候,程序是没有问题,判断库存,接着判断是否重复秒杀了,这两步是没有问题的,但是在多线程的时候,例如当库存只有1个的时候,突然来了多个用户进行秒杀,判断完库存后,都发现库存还有一个,接着进行是否秒杀了的判断,都没有秒杀过后,那么这多个用户就会同时进行减库存了,然后就出现超卖的情况了。

首先来看看减库存的sql:

@Update("update miaosha_goods set stock_count = stockCount - 1 where goods_id = #{goodsId}")
public int resetStock(MiaoshaGoods g);

在并发环境下,如果多个人同时执行这个SQL语句,那么就会导致值变成负的,可以加个条件:stockCount > 0

@Update("update miaosha_goods set stock_count = stockCount - 1 where goods_id = #{goodsId} and stockCount > 0")
public int resetStock(MiaoshaGoods g);

解读:库存大于0的时候才进行更新。数据库本身对该这条语句加锁,就不会出现多个线程同时更新一条记录的情况。

但是这样还是会出现问题:如果库存有10个商品,此时接口同时有了两个请求,首先会去判断库存,两个请求都能判断成功(因为库存剩10个),接着两个线程同时进行判断是否秒杀到了,由于两个线程是没有秒杀到的,所以接着同时进行减库存了,这样两个线程都能减库存成功并下订单。此时就相当于一个用户发起多个秒杀的请求,秒杀到了多个商品。

思路:(用数据库的唯一索引)我们需要限制一个用户只能秒杀一个商品,可以在秒杀订单表上加上唯一的索引,第一个记录可以插入进来,第二个记录就插不进来,插不进来之后,创建订单详情的事务方法就会报错,报错就会回滚。

索引:u_uid_gid   用户_id goods_id

索引类型:Unique

索引方式:BTree

优化:判断是否有秒杀到的时候,可以不去查询数据库,而是去查缓存,创建order缓存key,不需要设置有效期时间:

public class OrderKey extends BasePrefix {public OrderKey(String prefix) {super(prefix);}public static OrderKey getMiaoshaOrderByUidGid = new OrderKey("moug");
}

当生成订单的时候,将订单写入到了缓存里去,所以在getMiaoshaOrderByUserIdGoodsId中去缓存里取:

public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(long userId, long goodsId) {return redisService.get(OrderKey.getMiaoshaOrderByUidGid, ""+userId+"_"+goodsId, MiaoshaOrder.class);
}

生成订单之后,需要将订单给写入进去:(在orderServer中的生成订单方法中加上)

redisService.set(OrderKey.getMiaoshaOrderByUidGid, ""+user.getId()+"_"+goods.getId(), miaoshaOrder);

此时成功解决卖超这个问题了。

Java Seckill Module:Order details are static and Resolve purchases beyond相关推荐

  1. java操作Excel-poi:无法解析符号/方法Cannot resolve symbol ‘‘、Cannot resolve method ‘‘

    侵删. 错误: HSSFCell.CELL_TYPE_STRING.HSSFCell.CELL_TYPE_BOOLEAN和HSSFCell.CELL_TYPE_NUMERIC无法解析 解决办法: 使用 ...

  2. Java SE 9:使用IntelliJ IDE开发和测试模块之间的隐式可读性(第5部分)

    I have already discussed many theoretical concepts about "Java 9 Module System" and also d ...

  3. android 静态方法 构造方法,android基础-Java篇02:类和对象、构造方法、访问权限控制、重载、this关键字、static关键字...

    一.类和构造方法 (类和对象在百度百科已经有详细的介绍,这里只做简单的描述以及帮助理解:百度百科:类和对象,需要注意的是,百度百科类和对象的举例中都是C++,书写格式不要和Java混淆!) 什么是类? ...

  4. java public main_JAVA:public static void main(String args[]) 详解

    JAVA中的主函数,所有java程序的运行起点就是这个方法,除了args这个名字可以不一样外,其他必须是这样. 主函数的一般写法如下: public static void main(String[] ...

  5. 悦然插件资源分享:WooCommerce Order Details订单详情插件

    使用WooCommerce+wordpress建站是一种非常好的独立电商网站方案,但是默认情况下WooCommerce商城插件的功能比较简单,使用起来不是特别方便.今天悦然建站给大家分享一个免费算下的 ...

  6. 如何解决java.lang.NoClassDefFoundError:Java 9中的javax / xml / bind / JAXBException

    本文翻译自:How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException in Java 9 I have s ...

  7. java 虚拟机类型的卸载_《深入理解Java虚拟机》:类加载和初始化(二)

    <深入理解Java虚拟机>:类加载和初始化(二) 在去年看<深入理解Java虚拟机>的时候,写过一篇关于类加载和初始化的博客,最近又在看这一块的知识,发现还是有很多东西没有理解 ...

  8. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  9. Java基础篇:面向对象

    文章目录 学习面向对象内容的三条主线 面向过程(POP)与面向对象(OOP) 面向对象的思想概述 Java类和对象 创建Java自定义类 对象的创建和使用 对象的创建和使用:匿名对象 类的成员之一:属 ...

最新文章

  1. 广东科技学院专插本c语言考卷_广东科技学院第二届红色文化节之红色影视经典配音大赛决赛...
  2. DATEIF实例说明5
  3. mysql引擎层存储层_MySQL存储底层技术:InnoDB底层原理解读
  4. mysql的默认sid_默认实例(SID)已经设置,空实例默认连接时却连接不上?
  5. 内存泄露检测工具--VisualC++ debugger 和 CRT 库
  6. 【网络编程】之七、select聊天室
  7. 1075 链表元素分类 (25 分)
  8. python方差分析模型的预测结果中endog表示_python时间序列分析
  9. 程序员入门c语言还是java,先学java还是c语言?入门学哪种语言?
  10. 使用Jsoup完成网页爬虫
  11. MySQL数据库环境变量设置
  12. .log 合并或 .txt 合并
  13. 深度linux deepin15.2,从其它Deepin版本升级到深度Deepin 15.11操作系统的方法
  14. 亚马逊服务器升降配和增/减磁盘
  15. JAVA通过COM接口操作PPT
  16. jQuery API .append()
  17. 分析 | 高通骁龙845已发布,明年智能手机会变成什么样
  18. HADOOP读写性能测试
  19. 循环调用scrapy框架出现的问题:twisted.internet.error.ReactorNotRestartable,解决方法
  20. Java中如何创建自定义的注解学习笔记(MD版)

热门文章

  1. 修改Oracle用户默认表空间
  2. win+R键常见命令
  3. Windows7下SVN下载安装
  4. 梦到娭毑_原水_新浪博客
  5. xdd和go-cqhttp扫码登录提示密码错误或账号被冻结解决方法
  6. js分页页码显示逻辑实现的两种方法
  7. 苹果那么贵为什么还那么多人买
  8. redis setnx java_一步步实现单机redis的分布式锁(setnx)
  9. openid转换接口——公众号迁移(PHP接口)
  10. 电动自行车乘员头盔做T/SEIA003测试多少钱