为秒杀做优化,为秒杀订单加缓存
package com.mydre.miaosha.redis;
public class OrderKey extends BasePrefix{
private OrderKey(String prefix){
super(prefix);
}
public static OrderKey getMiaoshaOrderByUidGid = new OrderKey("moug");
}
在OrderService中:
//判断是否秒杀到了
public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(Long userId, long goodsId) {
//return orderDao.getMiaoshaOrderByUserIdGoodsId(userId, goodsId);
return redisService.get(OrderKey.getMiaoshaOrderByUidGid, "" + userId + "_" + goodsId, MiaoshaOrder.class);
}
//生成订单成功之后写入redis缓存
redisService.set(OrderKey.getMiaoshaOrderByUidGid, "" + user.getId() + "_" + goodsVo.getId(), miaoshaOrder);
开始订单详情静态化
首先定义OrderDetailVo类:
package com.mydre.miaosha.vo;
import com.mydre.miaosha.domain.OrderInfo;public class OrderDetailVo {
private GoodsVo goodsVo;
private OrderInfo orderInfo;
定义OrderController类:
@Controller
@RequestMapping("/order")
public class OrderController {
@Autowired
OrderService orderService;
@Autowired
GoodsService goodsService;
//首先分析需求,订单详情中需要订单相关信息和商品相关信息
@RequestMapping("detail")
@ResponseBody
public Result<OrderDetailVo> info(MiaoshaUser miaoshaUser, @RequestParam("orderId")long orderId){
if(miaoshaUser == null){
return Result.error(CodeMsg.SESSION_ERROR);
}
//通过订单号找到订单
OrderInfo orderInfo = orderService.getOrderById(orderId);
if(orderInfo == null){
return Result.error(CodeMsg.ORDER_NOT_EXIST);
}
//通过订单找到商品id
long goodsId = orderInfo.getGoodsId();
//通过商品id找到商品(通过商品Service)
GoodsVo goodsVo = goodsService.getOneGoodsVoById(goodsId);
OrderDetailVo orderDetailVo = new OrderDetailVo();
orderDetailVo.setGoodsVo(goodsVo);
orderDetailVo.setOrderInfo(orderInfo);
return Result.success(orderDetailVo);
}
}
一、查找订单详情的三个步骤:
①通过订单号找订单
@Select("select * from order_info where id=#{orderId}")
public OrderInfo getOrderById(@Param("orderId")long orderId);//这里需要加上一个@Param参数
②通过订单找商品号
long goodsId = orderInfo.getGoodsId();
③通过商品id找商品
@Select("select g.*, mg.stock_count, mg.miaosha_price, mg.start_date, mg.end_date from miaosha_goods mg left join goods g on mg.goods_id = g.id where mg.goods_id = #{id}")
public GoodsVo getOneGoodsVoById(@Param("id")long goodsId);
二、解决卖超的情况,最终在数据库层面最保险。
①一个用户发两个请求(为mysql数据库加唯一性索引)
②两个用户同时秒杀一个商品(判断 库存是否大于0)
GoodsDao中:
@Update("update miaosha_goods set stock_count=stock_count-1 where goods_id = #{goods_id} and stock_count > 0")
public void reduceStock(@Param("goods_id")long goods_id);
三、当点击秒杀时,进行后台处理,生成订单并定位到订单详情页(window.location.href=),附带传递参数:订单id。
在订单详情页面,使用$(function(){doSomething()}); 方法,在页面刚刚初始化的时候就以GET方式发起ajax请求,该请求负责调用后台获取数据,并在success回调函数中执行render()函数完成页面的渲染(占坑的过程,把静态页面中的坑填满,每个坑都可能是一个有id的节点)。
<script>
$(function(){
getOrderDetail();//能够保证在页面刚刚初始化的时候就被渲染(ajax异步获取数据)
});
function getOrderDetail(){
var orderId = getQueryString("orderId");//获取url中指定名称的参数
$.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('客户端请求有误');
}
});
}
function render(detail){
var goodsVo = detail.goodsVo;
var orderInfo = detail.orderInfo;
var goodsName = goodsVo.goodsName;
var orderPrice = goodsVo.miaoshaPrice;
var createDate = orderInfo.createDate;
var orderStatus = orderInfo.status;
//拿到服务端数据以后,即可以填充对象了
$("#goodsName").text(goodsName);
$("#goodsImg").attr("src", goodsVo.goodsImg);
$("#orderPrice").text(orderPrice);
$("#createDate").text(new Date(createDate).format("yyyy-MM-dd hh:mm:ss"));
$("#orderStatus").text(orderStatus);
}
</script>