从零搭建秒杀服务

1. 前言

目的:该项目只用于技术交流,不用于过多商业用途。 

适用:可用于简历亮点、毕业答辩等。

2. 项目成果

2.1 秒杀主页

包含5个功能点:

①、Product Name:秒杀商品名称

②、Product Image:秒杀商品图片

③、Price:秒杀价格

④、Seckill starts in:距离秒杀所剩时间

⑤、Seckill Now:秒杀按钮(核心逻辑)

部分不重要参数,没有做UI设计,只为功能而生

 2.2 秒杀架构

①、MySQL主从复制:一主二从

②、Redis缓存、Redis分布式锁

③、MQ异步处理库存、订单

 

3. 核心代码讲解

3.1 缓存预热

@Override
public void afterPropertiesSet() throws Exception {

    // 缓存秒杀商品
    List<SeckillGoods> seckillGoodsList = seckillMapper.queryAllSeckillGoods();
    for(SeckillGoods goods : seckillGoodsList) {
        String goodsId = goods.getId();
        Integer stock = goods.getGoodsStock();
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.put(CONSTANT.SECKILLGOODS, goodsId, stock);
    }

    // 缓存秒杀订单
    List<SeckillOrder> seckillOrderList = seckillMapper.queryAllSeckillOrder();
    for(SeckillOrder seckillOrder : seckillOrderList) {
        String userId = seckillOrder.getUserId();
        String goodsId = seckillOrder.getGoodsId();
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.put(CONSTANT.SECKILLORDER, userId + "," + goodsId, CONSTANT.SECKILLORDER);
    }

}

3.2 核心业务逻辑

@Override
public Map<String, String> buySeckillGoods(String userId, String goodsId) {

    Map result = new HashMap<String, String>();

    RLock lock = redisson.getLock(CONSTANT.SECKILLLOCK); // 拿不到会自己阻塞

    try {
        lock.lock();
        // 检查Redis秒杀商品是否有库存
        Integer stock = (Integer) redisTemplate.opsForHash().get(CONSTANT.SECKILLGOODS, goodsId);
        if(stock <= 0) {
            result.put("msg", "秒杀商品库存不足!");
            result.put("success", "400");
            return result;
        }

        // 检查该用户是否秒杀过该商品
        Object orderConstant = redisTemplate.opsForHash().get(CONSTANT.SECKILLORDER, userId + "," + goodsId);
        if(orderConstant != null) {
            result.put("msg", "该用户已经秒杀过该商品了!");
            result.put("success", "400");
            return result;
        }

        // Redis新增订单
        String orderId = UUID.randomUUID().toString();
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setId(orderId);
        seckillOrder.setGoodsId(goodsId);
        seckillOrder.setUserId(userId);

        redisTemplate.opsForHash().put(CONSTANT.SECKILLORDER, userId + "," + goodsId, CONSTANT.SECKILLORDER);

        // Redis减少库存
        redisTemplate.opsForHash().put(CONSTANT.SECKILLGOODS, goodsId, stock-1);

        // MQ处理库存和订单
        rabbitTemplate.convertAndSend("seckillGoodsExchange", "seckillGoodsRouting", seckillOrder);
        rabbitTemplate.convertAndSend("seckillOrderExchange", "seckillOrderRouting", seckillOrder);

    }catch (Exception e) {
        e.printStackTrace();
    }finally {
        lock.unlock(); // 解锁
    }

    result.put("msg", "秒杀商品成功!");
    result.put("success", "200");
    return result;
}

4. 其他

还存在其他的补充点(订单支付超时、订单真实支付、MQ消息问题、Redis单机问题等),如果喜欢请三连,我会继续更新。

需要完整代码或帮忙搭建环境,请留下邮箱。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值