Search in sources :

Example 1 with SeckillItem

use of com.whoiszxl.entity.SeckillItem in project shopzz by whoiszxl.

the class SeckillItemAdminController method save.

@SaCheckLogin
@PostMapping
@ApiOperation(value = "新增秒杀商品", notes = "新增秒杀商品", response = ResponseResult.class)
public ResponseResult<Boolean> save(@RequestBody SeckillItemSaveCommand bannerSaveCommand) {
    SeckillItem seckillItem = dozerUtils.map(bannerSaveCommand, SeckillItem.class);
    boolean saveFlag = seckillItemService.save(seckillItem);
    return ResponseResult.buildByFlag(saveFlag);
}
Also used : SeckillItem(com.whoiszxl.entity.SeckillItem) SaCheckLogin(cn.dev33.satoken.annotation.SaCheckLogin) ApiOperation(io.swagger.annotations.ApiOperation)

Example 2 with SeckillItem

use of com.whoiszxl.entity.SeckillItem in project shopzz by whoiszxl.

the class DefaultStockCacheServiceImpl method initItemStock.

@Override
public boolean initItemStock(Long seckillItemId) {
    try {
        SeckillItem seckillItem = seckillItemService.getById(seckillItemId);
        if (seckillItem == null) {
            log.info("秒杀商品不存在, id:{}", seckillItemId);
            return false;
        }
        if (seckillItem.getInitStockQuantity() < 1) {
            log.info("秒杀商品库存未配置, id:{}", seckillItemId);
            return false;
        }
        // 构建lua脚本
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(INIT_STOCK_LUA, Long.class);
        String stockCacheKey = RedisKeyPrefixConstants.CACHE_ITEM_STOCK + seckillItemId;
        String stockCacheAlignKey = RedisKeyPrefixConstants.CACHE_ITEM_STOCK_ALIGN + seckillItemId;
        List<String> keys = Lists.newArrayList(stockCacheKey, stockCacheAlignKey);
        Long result = (Long) redisUtils.execute(redisScript, keys, seckillItem.getInitStockQuantity().toString());
        if (result == null) {
            log.info("库存初始化失败,id:{}", seckillItemId);
            return false;
        }
        if (result == -997) {
            log.info("库存正在初始化中,本次初始化取消,id:{}", seckillItemId);
            return true;
        }
        if (result == 1) {
            log.info("库存初始化完成, id:{}", seckillItemId);
            return true;
        }
        return false;
    } catch (Exception e) {
        log.error("初始化库存发生异常:{}", e);
        return false;
    }
}
Also used : SeckillItem(com.whoiszxl.entity.SeckillItem) DefaultRedisScript(org.springframework.data.redis.core.script.DefaultRedisScript)

Example 3 with SeckillItem

use of com.whoiszxl.entity.SeckillItem in project shopzz by whoiszxl.

the class QueuedPlaceOrderServiceImpl method handlePlaceOrderTask.

@Override
@Transactional
public void handlePlaceOrderTask(SeckillPlaceOrderDTO seckillPlaceOrderDTO) {
    try {
        // 再次校验秒杀活动与秒杀商品的有效性
        boolean allowFlag = checkSeckill(seckillPlaceOrderDTO.getSeckillId());
        AssertUtils.isTrue(allowFlag, "秒杀活动校验失败");
        allowFlag = checkSeckillItem(seckillPlaceOrderDTO.getSeckillItemId());
        AssertUtils.isTrue(allowFlag, "秒杀商品校验失败");
        // 缓存中获取秒杀item,并将缓存中的库存设置上
        SeckillItem seckillItem = seckillItemService.getById(seckillPlaceOrderDTO.getSeckillItemId());
        // 进行库存实际扣减,因为通过token已经拦截了一次,可以直接进行数据库扣减,而不用走缓存扣减一次了
        boolean subDbFlag = seckillItemService.subDbStock(seckillPlaceOrderDTO.getSeckillItemId(), seckillPlaceOrderDTO.getQuantity());
        AssertUtils.isTrue(subDbFlag, "库存扣减失败");
        // 订单持久化
        SeckillOrder seckillOrder = buildSeckillOrder(seckillItem, seckillPlaceOrderDTO, seckillPlaceOrderDTO.getMemberId());
        boolean saveFlag = seckillOrderService.save(seckillOrder);
        if (!saveFlag) {
            ExceptionCatcher.catchValidateEx(ResponseResult.buildError("下单失败"));
        }
        // 如果taskKey的值为0,则说明还没执行完成,则设置为1
        Object taskValueObj = redisUtils.getObj(RedisKeyPrefixConstants.TASK_SECKILL_PLACE_ORDER_MQ + seckillPlaceOrderDTO.getTaskKey());
        if ("0".equals(taskValueObj)) {
            redisUtils.set(RedisKeyPrefixConstants.TASK_SECKILL_PLACE_ORDER_MQ + seckillPlaceOrderDTO.getTaskKey(), "1");
        }
        // 将订单ID设置到Redis中
        redisUtils.setEx(RedisKeyPrefixConstants.TASK_SECKILL_PLACE_ORDER_MQ_ORDER_ID + seckillPlaceOrderDTO.getTaskKey(), seckillOrder.getId().toString(), 24, TimeUnit.HOURS);
        log.info("handlePlaceOrderTask|MQ消费秒杀订单任务处理完成|{}", seckillPlaceOrderDTO);
    } catch (Exception e) {
        // 发生异常,设置为-1
        Object taskValueObj = redisUtils.getObj(RedisKeyPrefixConstants.TASK_SECKILL_PLACE_ORDER_MQ + seckillPlaceOrderDTO.getTaskKey());
        if (taskValueObj != null && "0".equals(taskValueObj)) {
            redisUtils.set(RedisKeyPrefixConstants.TASK_SECKILL_PLACE_ORDER_MQ + seckillPlaceOrderDTO.getTaskKey(), "-1");
        }
        log.info("handlePlaceOrderTask|MQ消费秒杀订单任务处理发生异常|{}", seckillPlaceOrderDTO, e);
        ExceptionCatcher.catchValidateEx(ResponseResult.buildError("下单失败"));
    }
}
Also used : SeckillItem(com.whoiszxl.entity.SeckillItem) SeckillOrder(com.whoiszxl.entity.SeckillOrder) Transactional(org.springframework.transaction.annotation.Transactional)

Example 4 with SeckillItem

use of com.whoiszxl.entity.SeckillItem in project shopzz by whoiszxl.

the class DefaultPlaceOrderServiceImpl method doPlaceOrder.

@Override
public Long doPlaceOrder(Long memberId, SeckillOrderSubmitCommand seckillOrderSubmitCommand) {
    boolean allowFlag = checkSeckill(seckillOrderSubmitCommand.getSeckillId());
    AssertUtils.isTrue(allowFlag, "秒杀活动校验失败");
    allowFlag = checkSeckillItem(seckillOrderSubmitCommand.getSeckillItemId());
    AssertUtils.isTrue(allowFlag, "秒杀商品校验失败");
    // 缓存中获取秒杀item,并将缓存中的库存设置上
    SeckillItemCache seckillItemCache = seckillItemCachedService.getCachedSeckillItem(seckillOrderSubmitCommand.getSeckillItemId(), null);
    putStockToItem(seckillItemCache.getSeckillItem());
    SeckillItem seckillItem = seckillItemCache.getSeckillItem();
    boolean preSubCacheFlag = false;
    try {
        // 进行库存预扣减
        preSubCacheFlag = stockCacheService.subCacheStock(seckillOrderSubmitCommand.getSeckillItemId(), seckillOrderSubmitCommand.getQuantity());
        AssertUtils.isTrue(preSubCacheFlag, "库存预扣减失败");
        // 进行库存实际扣减
        boolean subDbFlag = seckillItemService.subDbStock(seckillOrderSubmitCommand.getSeckillItemId(), seckillOrderSubmitCommand.getQuantity());
        AssertUtils.isTrue(subDbFlag, "库存扣减失败");
        // 持久化订单
        SeckillOrder seckillOrder = buildSeckillOrder(seckillItem, seckillOrderSubmitCommand);
        boolean saveFlag = seckillOrderService.save(seckillOrder);
        if (!saveFlag) {
            ExceptionCatcher.catchValidateEx(ResponseResult.buildError("下单失败"));
        }
        return seckillOrder.getId();
    } catch (Exception e) {
        // 如果预下单成功了,回滚缓存里的库存数量
        if (preSubCacheFlag) {
            boolean recoverFlag = stockCacheService.addCacheStock(seckillOrderSubmitCommand.getSeckillItemId(), seckillOrderSubmitCommand.getQuantity());
            if (!recoverFlag) {
                log.error("预扣减库存恢复失败,用户ID:{}, 秒杀商品ID:{}, 秒杀数量:{}", memberId, seckillOrderSubmitCommand.getSeckillItemId(), seckillOrderSubmitCommand.getQuantity());
            }
            ExceptionCatcher.catchValidateEx(ResponseResult.buildError("下单失败"));
        }
    }
    return null;
}
Also used : SeckillItem(com.whoiszxl.entity.SeckillItem) SeckillOrder(com.whoiszxl.entity.SeckillOrder) SeckillItemCache(com.whoiszxl.cqrs.cache.SeckillItemCache)

Example 5 with SeckillItem

use of com.whoiszxl.entity.SeckillItem in project shopzz by whoiszxl.

the class SeckillItemCachedServiceImpl method loadDb.

private SeckillItemCache loadDb(Long seckillItemId) {
    DistributedLock lock = distributedLockFactory.getDistributedLock(RedisKeyPrefixConstants.LOCK_GET_ITEM_FROM_DB + seckillItemId);
    try {
        boolean isLockSuccess = lock.tryLock(1, 5, TimeUnit.SECONDS);
        if (!isLockSuccess) {
            return new SeckillItemCache().tryLater();
        }
        SeckillItem seckillItem = seckillItemService.getById(seckillItemId);
        SeckillItemCache seckillItemCache;
        if (seckillItem == null) {
            seckillItemCache = new SeckillItemCache().notExist();
        } else {
            seckillItemCache = new SeckillItemCache().with(seckillItem);
        }
        redisUtils.setEx(RedisKeyPrefixConstants.CACHE_SECKILL_ITEM + seckillItemId, JsonUtil.toJson(seckillItemCache), 3, TimeUnit.SECONDS);
        log.info("从数据库加载数据,并保存到redis中:{}", seckillItemCache);
        return seckillItemCache;
    } catch (Exception e) {
        log.error("从数据库加载数据失败", e);
        return new SeckillItemCache().tryLater();
    } finally {
        lock.unlock();
    }
}
Also used : SeckillItem(com.whoiszxl.entity.SeckillItem) DistributedLock(com.whoiszxl.DistributedLock) SeckillItemCache(com.whoiszxl.cqrs.cache.SeckillItemCache)

Aggregations

SeckillItem (com.whoiszxl.entity.SeckillItem)9 SeckillItemCache (com.whoiszxl.cqrs.cache.SeckillItemCache)4 SaCheckLogin (cn.dev33.satoken.annotation.SaCheckLogin)2 SeckillOrder (com.whoiszxl.entity.SeckillOrder)2 ApiOperation (io.swagger.annotations.ApiOperation)2 LocalDateTime (java.time.LocalDateTime)2 DistributedLock (com.whoiszxl.DistributedLock)1 DefaultRedisScript (org.springframework.data.redis.core.script.DefaultRedisScript)1 Scheduled (org.springframework.scheduling.annotation.Scheduled)1 Transactional (org.springframework.transaction.annotation.Transactional)1