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


    1.续秒杀业务准备

    1.1设置定时任务

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

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

    1.创建Job接口实现类

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

    在seckill包下创建timer.job包

    在seckill包下创建timer.config包

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

    1. @Slf4j
    2. public class SeckillInitialJob implements Job {
    3. @Autowired
    4. private SeckillSkuMapper skuMapper;
    5. @Autowired
    6. private SeckillSpuMapper spuMapper;
    7. @Autowired
    8. private RedisTemplate redisTemplate;
    9. /*
    10. RedisTemplate对象在保存数据到Redis时,会将当前数据序列化后保存
    11. 这样做的好处是将序列化后的数据保存到Redis,读写效率高,缺点是不能在Redis中修改数据
    12. 我们现在要预热的信息包含sku的库存数,这个库存数如果也用上面的序列化的方式保存
    13. 就会因为高并发情况下的线程安全问题引发"超卖"
    14. 解决方案,我们需要一个能够直接在Redis中减少库存的方法来避免超卖的发生
    15. SpringDataRedis提供一个可以直接在Redis中操作数值的对象:StringRedisTemplate
    16. 使用StringRedisTemplate向Redis中保存数据,数据都会以字符串的方式保存
    17. 又因为Redis可以直接操作数值类型的字符串,所以可以通过它实现直接修改库存数
    18. 这样就不需要编写java代码判断了,再配合Redis天生单线程的特性,避免线程安全问题,防止超卖
    19. */
    20. @Autowired
    21. private StringRedisTemplate stringRedisTemplate;
    22. @Override
    23. public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    24. // 当前方法是Quartz调度运行的,运行时是要预热的需求,所以秒杀还没有到时间
    25. // 我们设计的是提前5分钟预热
    26. // 所以我们要查询5分钟之后进行秒杀的商品信息
    27. LocalDateTime time = LocalDateTime.now().plusMinutes(5);
    28. // 查询这个时间所有的秒杀商品
    29. List seckillSpus = spuMapper.findSeckillSpusByTime(time);
    30. // 遍历所有即将进行秒杀的商品,将它们的库存数保存到Redis
    31. for (SeckillSpu spu : seckillSpus) {
    32. // 当前spu是商品的品类,并没有库存数
    33. // 库存数保存在具体规格商品表sku中,所以要先根据spuId查询sku列表
    34. List seckillSkus = skuMapper.
    35. findSeckillSkusBySpuId(spu.getSpuId());
    36. // 当前循环是变量spu的,查询到的sku列表需要再嵌套一层循环
    37. for (SeckillSku sku : seckillSkus) {
    38. log.info("开始将{}号sku商品的库存预热到Redis", sku.getSkuId());
    39. // 下面要确定当前sku的库存数的key
    40. // SeckillCacheUtils.getStockKey是能够获得事先准备好的库存key常量名称的方法
    41. // 所以skuStockKey可能是"mall:seckill:sku:stock:1"
    42. String skuStockKey=
    43. SeckillCacheUtils.getStockKey(sku.getSkuId());
    44. // 检查Redis中是否已经包含了这个key
    45. if(redisTemplate.hasKey(skuStockKey)){
    46. // 如果key已经存在,证明之前已经缓存过了,直接跳过即可
    47. log.info("{}号sku商品已经缓存过了",sku.getSkuId());
    48. }else{
    49. // 如果key不在Redis中,就要将sku的库存数保存到Redis
    50. // 这里要将库存数的字符串格式保存,以便后续直接在Redis中减少库存的操作
    51. // 设置过期时间,应该是秒杀活动时间,加5分钟,最好再加个随机数防雪崩
    52. stringRedisTemplate.boundValueOps(skuStockKey)
    53. .set(sku.getSeckillStock()+"",
    54. 125*60*1000+ RandomUtils.nextInt(10000),
    55. TimeUnit.MILLISECONDS);
    56. log.info("成功为{}号sku商品预热缓存",sku.getSkuId());
    57. }
    58. }
    59. // 上面sku库存数预热完成
    60. // 下面开始预热每个spu的随机码
    61. // 随机码的作用简单来说就是给访问spu设置一个随机的路径
    62. // 如果不知道这个随机的路径是无法访问我们spu信息的
    63. // 能够减少服务器的压力
    64. // 在缓存预热时我们的操作就是生成随机码并保存到Redis,以便在后续业务中获取
    65. // randCodeKey=mall:seckill:spu:url:rand:code:2
    66. String randCodeKey=SeckillCacheUtils.getRandCodeKey(spu.getS
  • 相关阅读:
    Rsync 与frp搭建远程备份服务和基本命令行操作示例
    性能测试准备方案
    R语言技能 | 不同数据类型的转换
    レレ / 蕾蕾
    iOS 17更新失败或无法更新怎么办?8 个解决方法快速解决!
    重新理解微服务之它还那么纯粹吗?
    深入理解MySQL数据库(Innodb存储引擎)
    解决json_decode解析返回null空值
    达梦数据库备份策略
    Solidity:智能合约中不正确的继承顺序
  • 原文地址:https://blog.csdn.net/TheNewSystrm/article/details/126751885