Springboot 如何自动上传秒杀商品数据到Redis中上架商品

这篇具有很好参考价值的文章主要介绍了Springboot 如何自动上传秒杀商品数据到Redis中上架商品。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、概述

如下图秒杀活动:

Springboot 如何自动上传秒杀商品数据到Redis中上架商品
在这个秒杀活动中,需要自动上架一定时间段的商品,我们如何实现自动上传呢?

我们可以通过定时任务来实现的。在秒杀活动开始前,需要将商品信息存储到数据库中,并设置好库存和价格等信息。然后,可以通过定时任务的方式,每天定时从数据库中读取商品信息,并将其上传到秒杀页面上。这样,就可以实现自动上传商品的功能了。

二、Springboot定时任务配置

由于秒杀活动涉及的商品比较多,采用异步上传的方式

@EnableAsync
// 开启定时任务
@EnableScheduling
// 配置类
@Configuration
public class ScheduledConfig {

}

三、秒杀表设计

1. 秒杀场次表,主要展示哪个时间段进行秒杀

Springboot 如何自动上传秒杀商品数据到Redis中上架商品

CREATE TABLE `kmall_coupon`.`sms_seckill_session`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '场次名称',
  `start_time` datetime(0) NULL DEFAULT NULL COMMENT '每日开始时间',
  `end_time` datetime(0) NULL DEFAULT NULL COMMENT '每日结束时间',
  `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用状态',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '秒杀活动场次' ROW_FORMAT = Dynamic;

2 秒杀商品表,主要存储哪个时间段内进行秒杀的商品

与场次关联的字段是 promotion_session_id
Springboot 如何自动上传秒杀商品数据到Redis中上架商品

四、具体业务实现

1. 流程图

Springboot 如何自动上传秒杀商品数据到Redis中上架商品

2. 开启定时任务,上传商品到redis

由于是异步开启定时任务,在上架商品时采用了redisson分布式锁机制文章来源地址https://www.toymoban.com/news/detail-512468.html

@Slf4j
@Service
public class SeckillScheduled {


    @Autowired
    SeckillService seckillService;
    @Autowired
    RedissonClient redissonClient;

 
    /**
     * 秒杀商品定时上架,保证幂等性问题
     *  每天晚上3点,上架最近三天需要秒杀的商品
     *  当天00:00:00 - 23:59:59
     *  明天00:00:00 - 23:59:59
     *  后天00:00:00 - 23:59:59
     */
    @Scheduled(cron = "*/10 * * * * ? ")   
    public void uploadSeckillSkuLatest3Days() {
        // 重复上架无需处理
        log.info("上架秒杀的商品...");

        // 分布式锁(幂等性)
        RLock lock = redissonClient.getLock(SeckillConstant.UPLOAD_LOCK);
        try {
            lock.lock(10, TimeUnit.SECONDS);
            // 上架最近三天需要秒杀的商品
            seckillService.uploadSeckillSkuLatest3Days();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

3. 上架最近三天需要秒杀的商品

  1. 查询最近三天需要参加秒杀的场次+商品
  2. 上架场次信息
  3. 上架商品信息
@Override
public void uploadSeckillSkuLatest3Days() {
    // 1.查询最近三天需要参加秒杀的场次+商品
    R lates3DaySession = couponFeignService.getLates3DaySession();
    if (lates3DaySession.getCode() == 0) {
        // 获取场次
        List<SeckillSessionWithSkusTO> sessions = lates3DaySession.getData("data", new TypeReference<List<SeckillSessionWithSkusTO>>() {
        });
        // 2.上架场次信息
        saveSessionInfos(sessions);
        // 3.上架商品信息
        saveSessionSkuInfo(sessions);
    }
}
2.1 查询最近三天需要参加秒杀的场次+商品
  1. 计算最近三天起止时间
  2. 查询起止时间内的秒杀场次
  3. 组合秒杀关联的商品信息
 @Override
    public List<SeckillSessionEntity> getLates3DaySession() {
        // 计算最近三天起止时间
        String startTime = DateUtils.currentStartTime();// 当天00:00:00
        String endTime = DateUtils.getTimeByOfferset(2);// 后天23:59:59

        // 查询起止时间内的秒杀场次
        List<SeckillSessionEntity> sessions = baseMapper.selectList(new QueryWrapper<SeckillSessionEntity>()
                .between("start_time", startTime, endTime));

        // 组合秒杀关联的商品信息
        if (!CollectionUtils.isEmpty(sessions)) {
            // 组合场次ID
            List<Long> sessionIds = sessions.stream().map(SeckillSessionEntity::getId).collect(Collectors.toList());
            // 查询秒杀场次关联商品信息
            Map<Long, List<SeckillSkuRelationEntity>> skuMap = seckillSkuRelationService
                    .list(new QueryWrapper<SeckillSkuRelationEntity>().in("promotion_session_id", sessionIds))
                    .stream().collect(Collectors.groupingBy(SeckillSkuRelationEntity::getPromotionSessionId));

            sessions.forEach(session -> session.setRelationSkus(skuMap.get(session.getId())));
        }
        return sessions;
    }
2.2 上架场次信息
  1. 遍历场次
  2. 判断场次是否已上架(幂等性)
  3. 封装场次信息
  4. 上架 redisTemplate.opsForList().leftPushAll(key, skuIds);
private void saveSessionInfos(List<SeckillSessionWithSkusTO> sessions) {
        if (!CollectionUtils.isEmpty(sessions)) {
            sessions.stream().forEach(session -> {
                // 1.遍历场次
                long startTime = session.getStartTime().getTime();// 场次开始时间戳
                long endTime = session.getEndTime().getTime();// 场次结束时间戳
                String key = SeckillConstant.SESSION_CACHE_PREFIX + startTime + "_" + endTime;// 场次的key

                // 2.判断场次是否已上架(幂等性)
                Boolean hasKey = redisTemplate.hasKey(key);
                if (!hasKey) {
                    // 未上架
                    // 3.封装场次信息
                    List<String> skuIds = session.getRelationSkus().stream()
                            .map(item -> item.getPromotionSessionId() + "_" + item.getSkuId().toString())
                            .collect(Collectors.toList());// skuId集合
                    // 4.上架
                    redisTemplate.opsForList().leftPushAll(key, skuIds);
                }
            });
        }
    }
2.3 上架商品信息
  1. 查询所有商品信息
  2. 将查询结果封装成Map集合
  3. 绑定秒杀商品hash
  4. 遍历场次,遍历商品,判断商品是否已上架(幂等性)
  5. 封装商品信息
  6. 上架商品(序列化成json格式存入Redis中)
  7. 上架商品的分布式信号量,key:商品随机码 值:库存(限流)
private void saveSessionSkuInfo(List<SeckillSessionWithSkusTO> sessions) {
        if (!CollectionUtils.isEmpty(sessions)) {
            // 查询所有商品信息
            List<Long> skuIds = new ArrayList<>();
            sessions.stream().forEach(session -> {
                List<Long> ids = session.getRelationSkus().stream().map(SeckillSkuVO::getSkuId).collect(Collectors.toList());
                skuIds.addAll(ids);
            });
            R info = productFeignService.getSkuInfos(skuIds);
            if (info.getCode() == 0) {
                // 将查询结果封装成Map集合
                Map<Long, SkuInfoTO> skuMap = info.getData(new TypeReference<List<SkuInfoTO>>() {
                }).stream().collect(Collectors.toMap(SkuInfoTO::getSkuId, val -> val));
                // 绑定秒杀商品hash
                BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(SeckillConstant.SECKILL_CHARE_KEY);
                // 1.遍历场次
                sessions.stream().forEach(session -> {
                    // 2.遍历商品
                    session.getRelationSkus().stream().forEach(seckillSku -> {
                        // 判断商品是否已上架(幂等性)
                        String skuKey = seckillSku.getPromotionSessionId().toString() + "_" + seckillSku.getSkuId().toString();// 商品的key(需要添加场次ID前缀,同一款商品可能场次不同)
                        if (!operations.hasKey(skuKey)) {
                            // 未上架
                            // 3.封装商品信息
                            SeckillSkuRedisTO redisTo = new SeckillSkuRedisTO();// 存储到redis的对象
                            SkuInfoTO sku = skuMap.get(seckillSku.getSkuId());
                            BeanUtils.copyProperties(seckillSku, redisTo);// 商品秒杀信息
                            redisTo.setSkuInfo(sku);// 商品详细信息
                            redisTo.setStartTime(session.getStartTime().getTime());// 秒杀开始时间
                            redisTo.setEndTime(session.getEndTime().getTime());// 秒杀结束时间
                            // 商品随机码:用户参与秒杀时,请求需要带上随机码(防止恶意攻击)
                            String token = UUID.randomUUID().toString().replace("-", "");// 商品随机码(随机码只会在秒杀开始时暴露)
                            redisTo.setRandomCode(token);// 设置商品随机码

                            // 4.上架商品(序列化成json格式存入Redis中)
                            String jsonString = JSONObject.toJSONString(redisTo);
                            operations.put(skuKey, jsonString);

                            // 5.上架商品的分布式信号量,key:商品随机码 值:库存(限流)
                            RSemaphore semaphore = redissonClient.getSemaphore(SeckillConstant.SKU_STOCK_SEMAPHORE + token);
                            // 信号量(扣减成功才进行后续操作,否则快速返回)
                            semaphore.trySetPermits(seckillSku.getSeckillCount());
                        }
                    });
                });
            }
        }
    }

到了这里,关于Springboot 如何自动上传秒杀商品数据到Redis中上架商品的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • php - 超详细 thinkphp + redis 实现商品秒杀抢购功能,提供完整流程详细讲解及企业级功能示例源代码,环境准备、数据库表设计、并发压力测试等(新手小白一看就懂!)

    很多文章都已经过时了,而且还不讲原理,本文一次性说清楚。 很多电商系统几乎都有秒杀功能,那么用 tp+redis 怎么实现呢? 本文详细讲解商品秒杀功能的实现,提供详细的代码及注释,包括环境准备、环境搭建教程(已搭建的跳过即可)、数据库表设计、压力测试、示例

    2023年04月08日
    浏览(50)
  • chatgpt赋能python:使用Python来进行抢购,如何轻松秒杀商品

    在现代社会,大量的人们使用电商平台来完成他们的购物需求。然而,在疯狂的购物节日时,例如\\\"双11\\\",商品往往会被抢购一空。为此,许多人希望能够使用自动化脚本,在秒级别内完成商品的购买,以避免人工购物时的抢购高峰。 Python是一种优秀的编程语言,因为它可以

    2024年02月07日
    浏览(51)
  • 抓取电商产品数据的方法|电商平台商品详情数据|批量上架|商品搬家|电商封装API数据采集接口更高效安全的数据采集

    大量级电商数据采集时使用电商API接口有以下优势: 1. 数据准确性:通过电商API接口获取数据,可以保证数据的准确性和实时性,避免了手动采集可能出现的错误和延迟。 2. 自动化采集:API接口可以实现自动化的数据获取和更新,大大减少了人工操作的时间成本,提高了数

    2024年04月27日
    浏览(43)
  • SpringBoot+RabbitMQ+Redis实现秒杀功能

    传统处理:如果不涉及到redis的话,最初的用户请求进来的流程大概是先去数据库判断下当前用户是否已经秒杀过当前商品,如果秒杀过的话则返回秒杀失败不能重复秒杀,否则的话则执行减库存,下订单等步骤。 然而秒杀场景下,用户量非常庞大直接访问数据库的可能会使

    2024年02月02日
    浏览(36)
  • 如何在上架App之前设置证书并上传应用

    在上架App之前想要进行真机测试的同学,请查看《iOS- 最全的真机测试教程》,里面包含如何让多台电脑同时上架App和真机调试。 P12文件的使用详解 注意: 同样可以在Build Setting 的sign中设置证书,但是有点麻烦,建议就在General中设置证书,比较方便,还可以查看错误的地方

    2024年02月07日
    浏览(54)
  • 如何实现批量获取电商数据自动化商品采集?如何利用电商数据API实现业务增长?

    随着电子商务的快速发展,数据已经成为了电商行业最重要的资产之一。在这个数据驱动的时代,电商数据API(应用程序接口)的作用日益凸显。通过电商数据API,商家能够获取到大量关于消费者行为、产品表现、市场趋势等有价值的信息,进而利用这些数据优化业务策略,

    2024年02月19日
    浏览(51)
  • 谷粒商城--整合Elasticsearch和商品的上架

    索引,类型,文档是什么? 索引就像是Mysql中的库 类型就像是Mysql中的表 文档就像是数据 属性就是列名 所有的数据都是Json格式 倒排索引 简约理解版本2.0 正向索引 ,数据库创建索引,增加搜索速度。 倒排索引 是根据去找文档,然后记录一下出现的位置和次数。 根

    2023年04月08日
    浏览(54)
  • SpringBoot 结合RabbitMQ与Redis实现商品的并发下单【SpringBoot系列12】

    SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见。 程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发 1 项目准备 SpringBoot 整合 RabbitMQ 消息队列【SpringBoot系列11】本文章 基于这个项目来开

    2023年04月19日
    浏览(38)
  • 高性能商品秒杀抢购系统

    完整资料进入【数字空间】查看——baidu搜索\\\"writebug\\\" Go+iris+rabbbitmq+mysql构建高性能商品秒杀抢购系统 1. 课程目标 应用GoWeb快速构建秒杀系统 全流程应用开发及架构化设计思维梳理 逐级优化,轻松应对“秒杀”及类似高并发场景 2. 知识储备 RabbitMQ入门 Iris入门 3. 基础功能开发

    2024年02月11日
    浏览(43)
  • 商城-学习整理-高级-商城业务-商品上架es(十)

    只有上架的商品才可以在前台展示,不上架的在后台管理系统。上架就是放到ES中。 1、商品 Mapping 分析:商品上架在 es 中是存 sku 还是 spu? 1)、检索的时候输入名字,是需要按照 sku 的 title 进行全文检索的 2)、检索使用商品规格,规格是 spu 的公共属性,每个 spu 是一样的

    2024年02月12日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包