JSD-2204-(业务逻辑开发)-续秒杀业务-消息队列-Day14

本文详细介绍了续秒杀业务的准备工作,包括设置Quartz定时任务将库存和随机码保存到Redis,以及开发查询秒杀商品详情和Sku列表的功能。此外,还探讨了消息队列在解决Dubbo远程调用性能问题中的角色,解释了消息队列的基本概念和特征,并列举了常见的消息队列软件。
摘要由CSDN通过智能技术生成

1.续秒杀业务准备

1.1设置定时任务

1.1.1将库存和随机码保存到Redis

利用Quartz将库存和随机码保存到Redis

1.创建Job接口实现类

2.创建配置类,配置JobDetail和Trigger

在seckill包下创建timer.job包

在seckill包下创建timer.config包

首先我们编写缓存预热的操作,在job包下创建类SeckillInitialJob

@Slf4j
public class SeckillInitialJob implements Job {
    @Autowired
    private SeckillSkuMapper skuMapper;
    @Autowired
    private SeckillSpuMapper spuMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    /*
    RedisTemplate对象在保存数据到Redis时,会将当前数据序列化后保存
    这样做的好处是将序列化后的数据保存到Redis,读写效率高,缺点是不能在Redis中修改数据
    我们现在要预热的信息包含sku的库存数,这个库存数如果也用上面的序列化的方式保存
    就会因为高并发情况下的线程安全问题引发"超卖"
    解决方案,我们需要一个能够直接在Redis中减少库存的方法来避免超卖的发生
    SpringDataRedis提供一个可以直接在Redis中操作数值的对象:StringRedisTemplate
    使用StringRedisTemplate向Redis中保存数据,数据都会以字符串的方式保存
    又因为Redis可以直接操作数值类型的字符串,所以可以通过它实现直接修改库存数
    这样就不需要编写java代码判断了,再配合Redis天生单线程的特性,避免线程安全问题,防止超卖
     */
    
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 当前方法是Quartz调度运行的,运行时是要预热的需求,所以秒杀还没有到时间
        // 我们设计的是提前5分钟预热
        // 所以我们要查询5分钟之后进行秒杀的商品信息
        LocalDateTime time = LocalDateTime.now().plusMinutes(5);
        // 查询这个时间所有的秒杀商品
        List<SeckillSpu> seckillSpus = spuMapper.findSeckillSpusByTime(time);
        // 遍历所有即将进行秒杀的商品,将它们的库存数保存到Redis
        for (SeckillSpu spu : seckillSpus) {
            // 当前spu是商品的品类,并没有库存数
            // 库存数保存在具体规格商品表sku中,所以要先根据spuId查询sku列表
            List<SeckillSku> seckillSkus = skuMapper.
                    findSeckillSkusBySpuId(spu.getSpuId());
            // 当前循环是变量spu的,查询到的sku列表需要再嵌套一层循环
            for (SeckillSku sku : seckillSkus) {
                log.info("开始将{}号sku商品的库存预热到Redis", sku.getSkuId());
                // 下面要确定当前sku的库存数的key
                // SeckillCacheUtils.getStockKey是能够获得事先准备好的库存key常量名称的方法
                // 所以skuStockKey可能是"mall:seckill:sku:stock:1"
                String skuStockKey=
                        SeckillCacheUtils.getStockKey(sku.getSkuId());
                // 检查Redis中是否已经包含了这个key
                if(redisTemplate.hasKey(skuStockKey)){
                    // 如果key已经存在,证明之前已经缓存过了,直接跳过即可
                    log.info("{}号sku商品已经缓存过了",sku.getSkuId());
                }else{
                    // 如果key不在Redis中,就要将sku的库存数保存到Redis
                    // 这里要将库存数的字符串格式保存,以便后续直接在Redis中减少库存的操作
                    // 设置过期时间,应该是秒杀活动时间,加5分钟,最好再加个随机数防雪崩
                    stringRedisTemplate.boundValueOps(skuStockKey)
                            .set(sku.getSeckillStock()+"",
                                    125*60*1000+ RandomUtils.nextInt(10000),
                                    TimeUnit.MILLISECONDS);
                    log.info("成功为{}号sku商品预热缓存",sku.getSkuId());
                }
            }
            // 上面sku库存数预热完成
            // 下面开始预热每个spu的随机码
            // 随机码的作用简单来说就是给访问spu设置一个随机的路径
            // 如果不知道这个随机的路径是无法访问我们spu信息的
            // 能够减少服务器的压力
            // 在缓存预热时我们的操作就是生成随机码并保存到Redis,以便在后续业务中获取
            // randCodeKey=mall:seckill:spu:url:rand:code:2
            String randCodeKey=SeckillCacheUtils.getRandCodeKey(spu.getSpuId());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值