同步库存扣减到数据库

news2024/9/21 4:28:21

跟接上文:
并发情况下的库存扣减

一 库存扣减

public DefaultTreeFactory.TreeActionEntity logic(String userId, Long strategyId, Integer awardId, String ruleValue, Date endDateTime) {
        log.info("规则过滤-库存扣减 userId:{} strategyId:{} awardId:{}", userId, strategyId, awardId);
        // 扣减库存
        Boolean status = strategyDispatch.subtractionAwardStock(strategyId, awardId, endDateTime);
        // true;库存扣减成功,TAKE_OVER 规则节点接管,返回奖品ID,奖品规则配置
        if (status) {
            log.info("规则过滤-库存扣减-成功 userId:{} strategyId:{} awardId:{}", userId, strategyId, awardId);

            // 写入延迟队列,延迟消费更新数据库记录。【在trigger的job;UpdateAwardStockJob 下消费队列,更新数据库记录】
            strategyRepository.awardStockConsumeSendQueue(StrategyAwardStockKeyVO.builder()
                    .strategyId(strategyId)
                    .awardId(awardId)
                    .build());

            // 注意;根据数据库表中配置走不同的节点。目前数据库配置 ALLOW 是走到下一个节点。
            return DefaultTreeFactory.TreeActionEntity.builder()
                    .ruleLogicCheckType(RuleLogicCheckTypeVO.TAKE_OVER)
                    .strategyAwardVO(DefaultTreeFactory.StrategyAwardVO.builder()
                            .awardId(awardId)
                            .awardRuleValue(ruleValue)
                            .build())
                    .build();
        }

        // 如果库存不足,则直接返回放行
        log.warn("规则过滤-库存扣减-告警,库存不足。userId:{} strategyId:{} awardId:{}", userId, strategyId, awardId);
        return DefaultTreeFactory.TreeActionEntity.builder()
                .ruleLogicCheckType(RuleLogicCheckTypeVO.ALLOW)
                .build();
    }
public void awardStockConsumeSendQueue(StrategyAwardStockKeyVO strategyAwardStockKeyVO) {
        String cacheKey = Constants.RedisKey.STRATEGY_AWARD_COUNT_QUERY_KEY;
        RBlockingQueue<StrategyAwardStockKeyVO> blockingQueue = redisService.getBlockingQueue(cacheKey);
        RDelayedQueue<StrategyAwardStockKeyVO> delayedQueue = redisService.getDelayedQueue(blockingQueue);
        delayedQueue.offer(strategyAwardStockKeyVO, 3, TimeUnit.SECONDS);
    }

二 定时任务扫描扣减数据库库存

@Slf4j
@Component()
public class UpdateAwardStockJob {

    @Resource
    private IRaffleStock raffleStock;

//    @Scheduled(cron = "0/5 * * * * ?")
    public void exec() {
        try {
            StrategyAwardStockKeyVO strategyAwardStockKeyVO = raffleStock.takeQueueValue();
            if (null == strategyAwardStockKeyVO) return;
            log.info("定时任务,更新奖品消耗库存 strategyId:{} awardId:{}", strategyAwardStockKeyVO.getStrategyId(), strategyAwardStockKeyVO.getAwardId());
            raffleStock.updateStrategyAwardStock(strategyAwardStockKeyVO.getStrategyId(), strategyAwardStockKeyVO.getAwardId());
        } catch (Exception e) {
            log.error("定时任务,更新奖品消耗库存失败", e);
        }
    }

}
  public StrategyAwardStockKeyVO takeQueueValue() throws InterruptedException {
        String cacheKey = Constants.RedisKey.STRATEGY_AWARD_COUNT_QUERY_KEY;
        RBlockingQueue<StrategyAwardStockKeyVO> destinationQueue = redisService.getBlockingQueue(cacheKey);
        return destinationQueue.poll();
    }
<update id="updateStrategyAwardStock" parameterType="cn.bugstack.infrastructure.persistent.po.StrategyAward">
        update strategy_award
        set award_count_surplus = award_count_surplus - 1
        where strategy_id = #{strategyId} and award_id = #{awardId} and award_count_surplus > 0
 </update>

三 redis库存扣减到0,直接清空队列并修改数据库库存为0
在这里插入图片描述

@Autowired
    private RabbitTemplate rabbitTemplate;

    public void publish(String topic, BaseEvent.EventMessage<?> eventMessage) {
        try {
            String messageJson = JSON.toJSONString(eventMessage);
            rabbitTemplate.convertAndSend(topic, messageJson);
            log.info("发送MQ消息 topic:{} message:{}", topic, messageJson);
        } catch (Exception e) {
            log.error("发送MQ消息失败 topic:{} message:{}", topic, JSON.toJSONString(eventMessage), e);
            throw e;
        }
    }
@Slf4j
@Component
public class ActivitySkuStockZeroCustomer {

    @Value("${spring.rabbitmq.topic.activity_sku_stock_zero}")
    private String topic;

    @Resource
    private IRaffleActivitySkuStockService skuStock;

    @RabbitListener(queuesToDeclare = @Queue(value = "${spring.rabbitmq.topic.activity_sku_stock_zero}"))
    public void listener(String message) {
        try {
            log.info("监听活动sku库存消耗为0消息 topic: {} message: {}", topic, message);
            // 转换对象
            BaseEvent.EventMessage<Long> eventMessage = JSON.parseObject(message, new TypeReference<BaseEvent.EventMessage<Long>>() {
            }.getType());
            Long sku = eventMessage.getData();
            // 更新库存
            skuStock.clearActivitySkuStock(sku);
            // 清空队列 「此时就不需要延迟更新数据库记录了」todo 清空时,需要设定sku标识,不能全部清空。
            skuStock.clearQueueValue();
        } catch (Exception e) {
            log.error("监听活动sku库存消耗为0消息,消费失败 topic: {} message: {}", topic, message);
            throw e;
        }
    }

}
<update id="clearActivitySkuStock" parameterType="java.lang.Long">
        update raffle_activity_sku
        set stock_count_surplus = 0, update_time = now()
        where sku = #{sku}
    </update>
@Override
    public void clearQueueValue() {
        String cacheKey = Constants.RedisKey.ACTIVITY_SKU_COUNT_QUERY_KEY;
        RBlockingQueue<ActivitySkuStockKeyVO> destinationQueue = redisService.getBlockingQueue(cacheKey);
        destinationQueue.clear();
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1947358.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

结合el-upload上传组件,验证文件格式及大小

结合el-upload上传组件&#xff0c;验证文件格式及大小 效果如下&#xff1a; 代码如下&#xff1a; upgradeFirmwareInfo.vue页面 <template><div><el-dialog title"新增固件升级包" :visible.sync"dialogFormVisible"top"7vh&qu…

电商数据集成之电商商品信息采集系统架构设计||电商API接口

一、引言 本架构设计文档旨在阐述基于 Selenium 的电商商品信息采集系统的整体架构&#xff0c;包括系统视图、逻辑视图、物理视图、开发视图和进程视图&#xff0c;并提供一个简单的采集电商商品信息的 demo。该系统通过模拟浏览器行为&#xff0c;实现对电商商品信息的自…

力扣高频SQL 50题(基础版)第九题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第九题197. 上升的温度题目说明思路分析实现过程准备数据实现方式结果截图总结 力扣高频SQL 50题&#xff08;基础版&#xff09;第九题 197. 上升的温度 题目说明 Weather ---------------------- | Column Name…

从防范到防御异常场景处理机制终于闭环了

前言 为什么要做异常场景自动化监控&#xff1f; 怎么做&#xff1f; 做这件事情的意义! 前言 QA在异常场景的处理上&#xff0c;之前更多地侧重于防范&#xff0c;通过风险评估、异常测试等手段降低异常发生的概率。异常场景数据的自动化监控更多地侧重于防御&#xff0c…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第四十九章 平台总线总结回顾

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

matlab 小数取余 rem 和 mod有 bug

目录 前言Matlab取余函数1 mod 函数1.1 命令行输入1.2 命令行输出 2 rem 函数2.1 命令行输入2.2 命令行输出 分析原因注意 前言 在 Matlab 代码中mod(0.11, 0.1) < 0.01 判断为真&#xff0c;mod(1.11, 0.1) < 0.01判断为假&#xff0c;导致出现意料外的结果。 结果发现…

CCS(Code Composer Studio 10.4.0)编译软件中文乱码怎么解决

如果是所有文件都出现了中文乱码这时建议直接在窗口首选项中修改&#xff1a;选择"Window" -> "Preferences"&#xff0c;找到"General" -> "Workspace"&#xff0c;将"Text file encoding"选项设置为"Other&quo…

Android lmkd机制详解

目录 一、lmkd介绍 二、lmkd实现原理 2.1 工作原理图 2.2 初始化 2.3 oom_adj获取 2.4 监听psi事件及处理 2.5 进程选取与查杀 2.5.1 进程选取 2.5.2 进程查杀 三、关键系统属性 四、核心数据结构 五、代码时序 一、lmkd介绍 Android lmkd采用epoll方式监听linux内…

关于私域终局的几个观察 【后续加图】

01 私域流量的本质 每个人对「私域」的定义都不一样。 最初&#xff0c;大家认为私域其实就是把微商往高级了说&#xff0c;于是 2020 年我看到许多朋友一窝蜂到朋友圈卖货&#xff0c;冒出了一个段子叫「我们都活成了微商」。 最开始&#xff0c;我也以为「私域」只是微信…

微服务实现全链路灰度发布

一、实现步骤 再请求 Header 中打上标签&#xff0c;例如再 Header 中添加 "gray-tag: true" &#xff0c;其表示要进行灰度测试&#xff08;访问灰度服务&#xff09;&#xff0c;而其他则访问正式服务。在负载均衡器 Spring Cloud LoadBalancer 中&#xff0c;拿到…

普中51单片机:DS1302时钟芯片讲解与应用(十)

文章目录 引言基本特性什么是RAM&#xff1f;什么是涓流充电&#xff1f; 电路图和引脚说明通信协议以及工作流程寄存器控制寄存器日历/时钟寄存器 DS1302读写时序代码演示——数码管显示时分秒 引言 DS1302 是一款广泛使用的实时时钟 (RTC) 芯片&#xff0c;具有低功耗、内置…

Docker-Compose实现MySQL之主从复制

1. 主服务器(IP:192.168.186.77) 1.1 docker-compose.yml services:mysql-master:image: mysql:latest # 使用最新版本的 MySQL 镜像container_name: mysql-master # 容器的名称environment:MYSQL_ROOT_PASSWORD: 123456 # MySQL root 用户的密码MYSQL_DATABASE: masterd…

【科研】# Taylor Francis 论文 LaTeX template模版 及 Word模版

【科研写论文】系列 文章目录 【科研写论文】系列前言一、Word 模板&#xff08;附下载网址&#xff09;&#xff1a;二、LaTeX 版本方法1&#xff1a;直接网页端打开&#xff08;附网址&#xff09;方法2&#xff1a;直接下载到本地电脑上编辑下载地址说明及注意事项 前言 给…

【Git】merge合并分支

两个分支未修改同一个文件的同一处位置: Git自动合并 两个分支修改了同一个文件的同一处位置:产生冲突 例&#xff1a; 在master分支修改了main同时&#xff0c;feat分支也修改了相同的文件 合并的时候就会产生冲突 解决方法: Step1- 手工修改冲突文件&#xff0c;合并冲突内容…

C# 实现条件变量

C# 进程通信系列 第一章 共享内存 第二章 条件变量&#xff08;本章&#xff09; 第三章 消息队列 文章目录 C# 进程通信系列前言一、关键实现1、用到的主要对象2、初始化区分创建和打开3、变量放到共享内存4、等待和释放逻辑 二、完整代码三、使用示例1、线程同步控制2、进程…

物理机 gogs+jenkins+sonarqube 实现CI/CD

一、部署gogs_0.11.91_linux_amd64.tar.gz gogs官网下载&#xff1a;https://dl.gogs.io/ yum -y install mariadb-serversystemctl start mariadbsystemctl enable mariadbuseradd gittar zxvf gogs_0.11.91_linux_amd64.tar.gzcd gogsmysql -u root -p < scripts/mysql.…

减轻幻觉新SOTA,7B模型自迭代训练效果超越GPT-4,上海AI lab发布

LLMs在回答各种复杂问题时&#xff0c;有时会“胡言乱语”&#xff0c;产生所谓的幻觉。解决这一问题的初始步骤就是创建高质量幻觉数据集训练模型以帮助检测、缓解幻觉。 但现有的幻觉标注数据集&#xff0c;因为领域窄、数量少&#xff0c;加上制作成本高、标注人员水平不一…

大厂面试官问我:两个1亿行的文件怎么求交集?【后端八股文十五:场景题合集】

本文为【场景题合集】初版&#xff0c;后续还会进行优化更新&#xff0c;欢迎大家关注交流~ hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f…

第一百七十八节 Java IO教程 - Java符号链接、Java文件

Java IO教程 - Java符号链接 符号链接包含对另一个文件或目录的引用。 符号链接引用的文件称为符号链接的目标文件。 符号链接上的操作对应用程序是透明的。我们可以使用java.nio.file.Files类处理符号链接。 isSymbolicLink(Path p)方法检查指定路径指定的文件是否是符号链…

解决 MDCFilter 引起的 Shiro UnavailableSecurityManagerException 异常:将过滤器交给 Shiro 管理

若将自定义的 MDCFilter 注册到 FilterRegistrationBean 中&#xff0c;而又在 MDCFilter 中使用了和 Shiro 相关的操作&#xff08;如获取当前登录用户&#xff09;&#xff0c;此时会因为 MDCFilter 先于 SecurityManager 实例化导致出现 UnavailableSecurityManagerExceptio…