三勾商城秒杀说明JAVA版

秒杀系统的核心功能点:

1.商家创建活动,设置时间段,选择参与活动的商品,设置折扣、库存等;
2.用户端可以看到秒杀预告列表、商品秒杀详情页用户点击立即抢购;
3.如果库存充足,则创建订单成功,否则秒杀失败。
4.提交订单后超时未支付,系统会自动关闭订单,回滚库存。

秒杀系统的核心技术难点:

1.并发流量大,秒杀开始前后,系统的瞬间请求流量飙升。
2.数据库负担过重。
3.超卖的情况。
4.不支付抢占名额,导致商品未销售出去。

项目针对以上问题做的优化方案:

目前主要用到了redis,在秒杀活动中,Redis具有以下优势:

1.高速读写:Redis基于内存,读写速度非常快,可以处理高并发的请求。
2.高可靠性:Redis支持主从复制和数据持久化,可以实现数据备份和恢复,保证数据的可靠性和一致性。
3.高并发性:Redis采用单线程模型,避免了线程切换和锁竞争的问题,可以处理大量的并发请求。

首先获取秒杀商品规格库存时从redis中读取,降低数据库压力,代码如下:

//从redis中获取规则库存

skuVo.setSeckillStock(seckillCache.getSkuStock(sku.getSeckillProductSkuId()));

//从redis中获取规格库存,判断库存是否充足

Integer seckillStock = seckillCache.getSkuStock(product.getSeckillSku().getSeckillProductSkuId());
if(product.getTotalNum() > seckillStock){
    throw new BusinessException("很抱歉,秒杀商品库存不足");
}

//获取秒杀商品规格库存

public Integer getSkuStock(Integer seckillProductSkuId){
    //查询是否有商品改库存锁
    boolean exits = redisLock.selectLock(CommonRedisKey.getRedisKey(CommonRedisKey.SECKILL_SKU_UPDATE_STOCK,seckillProductSkuId));
    // 存在锁
    if(exits){
        try {
            Thread.sleep(1);//库存修改完毕后再查询,防止超卖
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //重新尝试
        this.getSkuStock(seckillProductSkuId);
    }
    String cacheKey = CommonRedisKey.getRedisKey(CommonRedisKey.SECKILL_SKU_STOCK,seckillProductSkuId);
    Object object = redisTemplate.opsForValue().get(cacheKey);
    if(object != null){
        return (Integer)object;
    }
    SeckillProductSku sku = productSkuService.getById(seckillProductSkuId);
    if(sku == null){
        return 0;
    }
    //秒杀库存
    Integer seckillStock = sku.getSeckillStock();
    redisTemplate.opsForValue().set(cacheKey, seckillStock);
    return seckillStock;
}

然后用户进行秒杀下单的时候,redis执行减库存操作,代码如下

/**
 * 减少库存
 * @param vo
 */
private void decStock(UpdateProductStockVo vo){
    //给商品改库存上锁
    boolean lock = redisLock.getLock(CommonRedisKey.getRedisKey(CommonRedisKey.SECKILL_SKU_UPDATE_STOCK,vo.getSkuSourceId()), 5);
    // 拿到锁
    if(lock){
        SeckillProductSku sku = productSkuService.getById(vo.getSkuSourceId());
        //减少redis中秒杀商品库存
        Long stock = seckillCache.decrSkuStock(sku.getSeckillProductSkuId(), vo.getTotalNum());
        //减少后库存
        if(stock < 0){
            throw new BusinessException("很抱歉,秒杀商品库存不足");
        }
        // 更新商品主表库存
        productService.update(new LambdaUpdateWrapper<SeckillProduct>().eq(SeckillProduct::getSeckillProductId, sku.getSeckillProductId())
                .setSql("`stock` = `stock` - " + vo.getTotalNum()));
        // 更新规格库存
        productSkuService.update(new LambdaUpdateWrapper<SeckillProductSku>().eq(SeckillProductSku::getSeckillProductSkuId, sku.getSeckillProductSkuId())
                .setSql("`seckill_stock` = `seckill_stock` - " + vo.getTotalNum()));
    }else {
        try {
            Thread.sleep(5);//等会再去拿锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //重新尝试
        this.decStock(vo);
    }
}

//减少redis中秒杀商品库存

public Long decrSkuStock(Integer seckillProductSkuId,Integer num){
    String cacheKey = CommonRedisKey.getRedisKey(CommonRedisKey.SECKILL_SKU_STOCK,seckillProductSkuId);
    //先查询再操作,避免不存在报错
    this.selectSkuStock(seckillProductSkuId,cacheKey);
    return redisTemplate.opsForValue().decrement(cacheKey, num);
}

//订单超时未付款自动取消,回退redis库存

//增加redis中秒杀商品库存
public Long addSkuStock(Integer seckillProductSkuId,Integer num){
    String cacheKey = CommonRedisKey.getRedisKey(CommonRedisKey.SECKILL_SKU_STOCK,seckillProductSkuId);
    //先查询再操作,避免不存在报错
    this.selectSkuStock(seckillProductSkuId,cacheKey);
    return redisTemplate.opsForValue().increment(cacheKey, num);
}

//后台修改或者删除商品后,删除redis中秒杀商品库存信息,同步数据库库存

public void deleteSkuStock(Integer seckillProductSkuId) {
    String cacheKey = CommonRedisKey.getRedisKey(CommonRedisKey.SECKILL_SKU_STOCK,seckillProductSkuId);
    redisTemplate.delete(cacheKey);
}    

另外还有其他要注意的点:

秒杀后不付款定时取消,回退库存等操作。这个时间可以设置短一点,以免长时间锁住库存不释放,导致回滚库存时活动已结束。

压力测试

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Javashop_jjj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值