Java电商秒杀系统及其优化(四)

商品列表页缓存实现

热点对象缓存

商品详情页静态化

解决卖超问题


商品列表页缓存实现

实现思路

先查看redis中是否有缓存,如果有,直接返回html页面对象,没有手动渲染模板,创建缓存,并返回html对象

@RequestMapping(value = "/to_list",produces = "text/html")
    @ResponseBody
    public String toList(HttpServletRequest request, HttpServletResponse response, Model model, MiaoShaUser user){
        model.addAttribute("user",user);
        //在有缓存的情况下,取出缓存
        String html = redisService.get(GoodsKey.goodsKeyPrefix, "", String.class);
        if(! StringUtils.isEmpty(html)) return html;

        //在没有缓存的时候,手动渲染,添加缓存
        List<GoodsVo> goodsVos = goodsService.listGoodsVo();
        model.addAttribute("goodsList",goodsVos);
        IWebContext ctx = new WebContext(request,response,request.getServletContext(),request.getLocale(),model.asMap());
        html = thymeleafViewResolver.getTemplateEngine().process("goods_list",ctx);//这里需要注入IContext
        if(!StringUtils.isEmpty(html)){
            redisService.set(GoodsKey.goodsKeyPrefix,"",html);
        }

        return html;
        //return "goods_list";
    }

1.produces = “text/html” 标注了返回值的类型,这里因为不再返回一个页面而是一个对象,所以要使用@Responsebody注解
2.渲染页面我们使用了ThymeleafViewResolver,这是框架准备好的,这里需要注入icontext

IWebContext ctx = new WebContext(request,response,request.getServletContext(),request.getLocale(),model.asMap());

3.这里缓存过期时间设置的是60秒,即60秒内这个页面的信息不会发生变化

流程(转载自https://blog.csdn.net/qq_46225886/article/details/107340734)

在这里插入图片描述

对象缓存

之前我们做的登陆页面的token,取出的token直接对应一个用户对象,这就是一个对象级缓存

    public MiaoShaUser getById(long id){
        //先从缓存中取
        MiaoShaUser user = redisService.get(MiaoShaUserKey.idPrefix, "" + id, MiaoShaUser.class);
        if(user != null) return user;

        //缓存中没有,从数据库中取,并且把它添加到缓存中
        user = miaoShaUserDao.getById(id);
        if(user != null) redisService.set(MiaoShaUserKey.idPrefix,"" + id,user);

        return user;
    }

更新缓存

修改密码场景,先修改数据库,再修改缓存(先更新token-user,再删除id-user)

public boolean updatePassword(long id,String formPass,String token){
        //取出user
        MiaoShaUser user = getById(id);
        //没有这个用户
        if(user == null) throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);

        //修改密码,更新数据库
        user.setPassword(MD5Util.formPassToDBPass(formPass,user.getSalt()));
        miaoShaUserDao.update(user);
        //更新缓存,token-user缓存(登陆用的)这个不能删除,id-user缓存删除
        redisService.set(MiaoShaUserKey.getTokenPrefix,token,user);
        redisService.delete(MiaoShaUserKey.idPrefix,id);

        return true;
    }

页面静态化

通常不使用第一种缓存方法,而是通过静态化处理,比较常用的技术有Vue。通过静态化处理,我们将页面缓存在客户端浏览器中,不需要与服务器交互就能访问到页面。

@RequestMapping(value = "/detail/{goodsId}")
    @ResponseBody
    public Result<GoodsDetailVo> toDetail(HttpServletRequest request, HttpServletResponse response, Model model, MiaoShaUser user, @PathVariable("goodsId") long goodsId){

        GoodsVo goodsVo = goodsService.getGoodsVoByGoodsId(goodsId);

        //秒杀开始、结束时间,当前时间
        long startDate = goodsVo.getStartDate().getTime();
        long endDate = goodsVo.getEndDate().getTime();
        long now = System.currentTimeMillis();

        //秒杀状态,0为没开始,1为正在进行,2为秒杀已经结束
        int miaoshaStatus = 0;
        //距离秒杀剩余的时间
        int remainSeconds = 0;

        if(now < startDate){
            //秒杀没开始,进行倒计时
            remainSeconds = (int) (startDate - now) / 1000;
        }else if(now > endDate){
            //秒杀已经结束
            miaoshaStatus = 2;
            remainSeconds = -1;
        }else {
            //秒杀进行时
            remainSeconds = 0;
            miaoshaStatus = 1;
        }
        GoodsDetailVo goodsDetailVo = new GoodsDetailVo();
        goodsDetailVo.setGoods(goodsVo);
        goodsDetailVo.setUser(user);
        goodsDetailVo.setMiaoshaStatus(miaoshaStatus);
        goodsDetailVo.setRemainSeconds(remainSeconds);

        return Result.success(goodsDetailVo);
    }

配置

#static
spring.resources.add-mappings=true
spring.resources.cache-period= 3600
spring.resources.chain.cache=true 
spring.resources.chain.enabled=true
spring.resources.chain.gzipped=true
spring.resources.chain.html-application-cache=true
spring.resources.static-locations=classpath:/static/

超卖问题

1.在更新库存的sql语句中加一个库存的判断

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

2.避免一个用户秒杀多次,在数据库添加唯一索引,绑定user_id和goods_id,这样同一个用户对同一个商品的秒杀订单是唯一的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值