库存减扣方案

Mybatis-plus入门 MyBatisPlus环境搭建的步骤?BaseMapper通过入门案例制作,MyBatisPlus的优点有哪些?MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率https有什么简单的办法可以自动生成实体类的GET、SET方法?Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发。 阅读详情

目录

库存减扣关键点

库存减扣时机

库存减扣方案

基于Redis+Lua脚本+MQ+数据库方案


库存减扣关键点

库存减扣关键点如下:

  • 同一个SKU,库存数量共享;
  • 剩余库存必须要大于等于本次扣减数量,否则会出现超卖现象;
  • 对同一个数量多用户并发扣减时,要注意并发安全,保证数据的一致性;
  • 类似于秒杀这样高QPS的扣减场景,要保证性能与高可用;
  • 对于购物车下单场景,多个商品库存批量扣减,要保证事务一致性;
  • 如果发生交易退款,保证库存扣减可以返还:
    • 返还的数据总量不能大于扣减总量;
    • 返还要保证幂等性;
    • 允许多次返还。

库存减扣时机

库存减扣时机需根据业务场景设计,通常有三种方案:

  • 加入购物车时减扣库存。将秒杀商品加入购物车,用户不一定购买,如果此时减扣库存,会造成库存被无效占用,使真正有购买欲望的用户因库存不足而无法下单。
  • 提交订单时减扣库存。用户提交下单请求,说明存在强烈的购买欲望,创建订单前先进行库存校验,库存不足则提示用户下单失败原因,库存足够则减扣库存,再通过MQ消息异步创建订单。该方案需要保证库存校验和库存减扣是原子性操作,否则会导致超卖,同时,需要设定支付失效,超时未支付则订单失效。
  • 支付订单时减扣库存。该方案可减少库存被无效占用,但会因为用户仅下单不支付而导致创建大量无效订单。

推荐方案:提交订单时减扣库存。

库存减扣方案

库存减扣方案主要有三种:

  • 基于数据库乐观锁方案
  • 基于Redis分布式锁+数据库方案
  • 基于Redis+Lua脚本+MQ+数据库方案(推荐)

基于Redis+Lua脚本+MQ+数据库方案

添加依赖

<!-- mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- mybatis-plus-generator -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

定义库存减扣参数

/**
 * 判断商品是否存在KEY标识
 */
public static final long EXISTS_FLAG=-2L;
/**
 * 配置库存缓存KEY前缀
 */
public static final String REDIS_KEY="STOCK:";
/**
 * 执行扣库存脚本
 */
public static String STOCK_LUA;

定义库存减扣Lua脚本

static {
    /**
     * 减扣库存LUA脚本
     * 库存(stock)-1:表示不限库存
     * 库存(stock) 0:表示没有库存
     * 库存(stock)大于0:表示剩余库存
     * @param 库存key
     * @return
     *      -3:表示库存未初始化
     *      -2:表示库存不足
     *      -1:表示不限库存
     *      大于等于0:表示剩余库存(扣减之后的剩余库存)
     */
    final StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("if(redis.call('exists',KEYS[1])==1)then");
    stringBuilder.append("  local stock=tonumber(redis.call('get',KEYS[1]));");
    stringBuilder.append("  local num=tonumber(ARGV[1]);");
    stringBuilder.append("  if(stock==-1)then");
    stringBuilder.append("      return -1;");
    stringBuilder.append("  end;");
    stringBuilder.append("  if(stock>=num)then");
    stringBuilder.append("      return redis.call('incrby',KEYS[1],0-num);");
    stringBuilder.append("  end;");
    stringBuilder.append("  return -2;");
    stringBuilder.append("end;");
    stringBuilder.append("return -3;");
    STOCK_LUA = stringBuilder.toString();
}

库存减扣代码实现

/**
 * 获取库存减扣后的剩余库存
 * @param batchNo 商品编号
 * @param expire 商品库存过期时长
 * @param num 商品库存减扣数量
 * @return 剩余库存:
 *      返回值大于等于0:表示剩余库存数量
 *      返回值-1:表示不限库存
 *      返回值-2:表示库存不足
 *      返回值-3:表示库存未初始化(即:商品库存不存在)
 */
private long getStock(String batchNo, long expire, long num){
    // 商品库存唯一标识
    final String key = REDIS_KEY + batchNo;
    // 获取商品库存剩余过期时长,返回-2表示商品库存不存在(即:库存未初始化)
    long expireKey = redisUtil.getExpireByKey(key);
    // expireKey==-2:表示key不存在,即:未初始化库存
    if(Objects.equals(EXISTS_FLAG, expireKey)){
        // 初始化商品库存,注意:此处是从数据库中获取商品库存数据
        redisUtil.set(key,2,expire);
        log.info("Redis未初始化库存,库存返回:{}",expireKey);
    }

    // 获取剩余库存数
    final Object obj = redisUtil.get(key);
    log.info("Redis初始化库存数:{}",String.valueOf(obj));
    // 减扣库存
    return stock(STOCK_LUA, key, num);
}

/**
 * 扣减之后剩余库存:-3表示库存未初始化,-2表示库存不足,-1表示不限库存,大于等于0表示剩余库存。
 * @param lua lua脚本
 * @param key 商品key
 * @param num 扣减数量
 * @return 剩余库存
 */
private long stock(String lua, String key, long num){
    try {
        RedisScript<Long> redisScript = new DefaultRedisScript<>(lua, Long.class);
        // 执行LUA脚本
        return redisUtil.executeLua(redisScript, Collections.singletonList(key), num);
    }catch (Exception e){
        e.printStackTrace();
        throw new GenericBusinessException("11001","库存减扣异常");
    }
}

注意:以上代码实现了基于Redis+Lua脚本的库存减扣,库存减扣成功后通过发送MQ消息的方式异步生成订单即可。

微服务高并发秒杀实战_基于令牌桶实现库存(1) return setResultError(“商品信息不存在!”);// 用户频率限制 setnx 如果key存在话if (!return setResultError(“访问次数过多,10秒后再实现重试!”);// 直接return,无需执行下面的version++操作// 先获取版本号// 减库存// 后续可以生成订单到订单表。。。 阅读详情

相关推荐

电商 - 高并发下订单商品库存扣减方案

开发一个电商库存系统时,我们最担心的就是高并发和防超卖了。

MinggeQingchun的博客 6165

库存扣减设计和下单

大家好,我是练习两年半的Java练习生,前面我们已经介绍了领域驱动和缓存设计,这一章我们将介绍秒杀设计过程中比较重要的一个部分:关于库存扣减。我们将会从一些库存设计的一些原则和方案入手,介绍有哪些方案,进行对比,然后再分析秒杀系统中具体的下单代码,下单代码中就涉及到库存的扣减。让我们一起来看看吧~好啦,以上就是本篇文章要介绍的所有内容,主要是将库存扣减的两种方式和下单的整体流程,认识秒杀设计的具体实现是怎么样的。如果大家还有什么问题如果大家还有什么问题,欢迎私信或者在评论区提出来,让我们一起学习进步!

m0_52963553的博客 2615

从零构建个性化AI助手:基于Mem0与本地大模型的记忆化实践

本文详细介绍了如何利用Mem0与本地大模型构建个性化AI助手,实现记忆化应用结构的实践方法。从开发环境搭建、记忆存储机制到个性化交互实现,提供了完整的解决方案和代码示例,帮助开发者在本地环境中创建能记住用户习惯和偏好的智能助手。

weixin_29214335的博客 470

库存扣减问题

本文主要参考和总结自沈剑大佬扣减相关的三篇文章以及拉勾教育潘新宇老师的《23讲搞定后台架构实战》12~15章节课程,完整参考见文末。 1、方案 1.1 方案一:根据商品 id 查询库存,校验库存是否足够后,利用数据库自己的字段减法实现 set 扣减 -- select stock_num from stock where sid=$sid # sid商品id(上游查询) update stock...

Lucky小黄人的博客 2596

Signoff Criteria --- ocv/aocv/pocv之AOCV介绍

Advanced on chip variation,相比较于OCV来说,对于悲观度的去除很有效。相比较与ocv对于整个design中的lauch/capture path设置统一的derate值,aocv通过将cell derate值与cell的逻辑深度以及实际的位置结合起来进行derate值的设定。那么这种derate如何能够设置到具体的cell呢,其实是我们在跑STA时候会读入相关的aocv lib file,里面有专门对相关的cell进行的aocv derate值的描述。> table: \

sinat_27691203的博客 7856

用 Python 和 uiautomation 实现微信批量发送

思路是这样,将要发送的人员名单(包括称呼)以及发送内容都维护到Excel里,程序运行时读取Excel里内容,自动搜索人员姓名(微信昵称或备注名),填入要发送的内容,拼接上称呼(如果需要的话)自动点击发送,这样轮巡直至名单人员全部发送完成。、

jankingdom的专栏 1471

库存扣减

扣减时机   何时扣减扣减库存,目前有两种主流方式: 方式1:下单减库存——即用户下单成功时减少库存数量 优点:用户体验好,系统逻辑简单; 缺点:会导致恶意下单或下单后却不买,使得真正有需求的用户无法购买,影响真实销量; 解决办法: 设置订单有效时间,若订单创建成功N分钟不付款,则订单取消,库存回滚; 限购,用各种条件来限制买家的购买件数,比如一个账号、一个ip,只能买一件; 风控,从技术角...

04stone37 4371

华为OD机试真题2025双机位A卷 Java&Go 实现【采购订单】

在一个采购系统中,采购申请(PR)需要经过审批后才能生成采购订单(PO)。每个PR包含商品的单价(假设相同商品的单价一定是一样的)及数量信息。系统要求对商品进行分类处理:单价高于100元的商品需要单独处理,单价低于或等于100元的相同商品可以合并到同一采购订单PO中。针对单价低于100的小额订单,如果量大可以打折购买。

MISAYAONE的博客 1260

画秒杀系统流程图

【代码】画秒杀系统流程图。

weixin_43999182的博客 2545

基于ESP32 蓝牙游戏手柄设计

介绍使用 ESP32 并通过 BLE 通信的 设计手持游戏手柄,包含原理图与代码

DT程序员的博客 2164

Obsidian与RAG:知识管理的未来之战

摘要: 本文对比了传统RAG、Obsidian和llm-wiki-skill三种知识管理方案。传统RAG依赖查询时临时检索,知识无法积累;Obsidian需人工整理,成本高但结构化强;llm-wiki-skill通过AI在摄入时自动编译知识为结构化Wiki,实现持续增值。核心差异在于知识处理时机——llm-wiki-skill将"查询时检索"转变为"摄入时编译",通过三层Markdown结构(sources/concepts/entities)和自动双向链接构建可进化

ZhangJiqun&191cm&85kg 627

Java 实现秒杀-订单、库存、支付顺序确定

Java 实现秒杀-订单、库存、支付顺序确定

叼着烟吻着你的香 1890

软件需求规格说明书(SRS)标准模板

《软件需求规格说明书(SRS)框架解析》摘要: 本文档系统阐述了SRS的标准结构,包含7大核心部分:1)引言(目的、背景和术语);2)总体描述(产品定位与用户特征);3)功能需求(模块化功能说明);4)非功能需求(性能、安全等指标);5)接口需求(用户/硬件/软件接口);6)其他技术要求;7)附录(图表与参考资料)。重点突出了功能需求模块的标准化描述模板(FR-01),以及安全需求中的HTTPS通信、SHA-256加密等关键指标。该框架为软件开发提供了明确的需求基准,涵盖从业务背景到技术实现的完整链条,是确

moton2017的博客 2893

电商库存扣减

方案1:在下单就锁定库存 优点:可以解决库存减扣问题 缺点:体验差,如果只下单未付款,库存被锁定,让有意愿购买的用户无从下单,对销售业务有很大影响; 方案2:支付后减扣库存 优点:防止恶意下单,只要有足够的实际库存,随便多少意向客户下单 缺点:下单页面显示的库存数可能不是最新的库存数,其他用户可能提示库存不足,可能出现超卖问题。 方案3:调起支付界面前锁定库存 ...

t_332741160的专栏 1万+

用 SAP-ABAP-1 把 ABAP 代码理解这件事交给 AI:从遗留代码到 ABAP Cloud 的开发加速器

SAP-ABAP-1是SAP推出的首个专用ABAP基础模型,专注于理解和解释ABAP代码,帮助开发者更快迁移和维护遗留系统。它强调ABAP Cloud合规编码实践,通过SAP AI Foundation提供访问,主要能力包括代码解释、业务语义理解和框架约束分析。相比通用模型,它能更好处理ABAP特有的版本差异、权限控制和扩展边界等问题。该模型可集成到多种开发环境中,支持文件化开发体验,并能与SAP Joule等工具协同工作,为ABAP团队提供智能辅助。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 3827

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

商城系统学习总结(1)——订单与库存在高并发场景下案例解析

一、 问题 一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品。如何保证库存在高并发的场景下是安全的? (1)不多发 (2)不少发 二、 下单的步骤 (1)下单 (2)下单同时预占库存 (3)支付 (4)支付成功真正减扣库存 (5)取消订单 (6)回退预占库存 三、 什么时候进行预占库存? (1)方案一:加入购物车的时候去...

科技D人生 5540

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Redis的一些高并发处理,QPS超过1万的读写

了解Redis高性能处理方案,qps超过1万的读写

weixin_43504955的博客 3010

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

高并发核心技术 - 订单与库存

问题:一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品。如何保证库存在高并发的场景下是安全的。1.不多发2.不少发 下单涉及的一些步骤1.下单2.下单同时预占库存3.支付4.支付成功真正减扣库存5.取消订单6.回退预占库存 什么时候进行预占库存方案一:加入购物车的时候去预占库存。方案二:下单的时候去预占库存。方...

weixin_30699955的博客 325

高并发下的订单与库存的处理

问题:一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品。如何保证库存在高并发的场景下是安全的。 1.不多发 2.不少发 下单涉及的一些步骤 1.下单 2.下单同时预占库存 3.支付 4.支付成功真正减扣库存 5.取消订单 6.回退预占库存 什么时候进行预占库存 方案一:加入购物车的时候去预占库存。 方案二...

林老师带你学编程 6551

设计一个100W QPS的架构

上图中描述了用户请求到服务器经历了三层的负载均衡,下边分别简单介绍一下这三种负载均衡。OSPF(开放式最短链路优先)是一个内部网关协议(Interior Gateway Protocol,简称 IGP)OSPF 通过路由器之间通告网络接口的状态来建立链路状态数据库,生成最短路径树,OSPF 会自动计算路由接口上的 Cost 值,但也可以通过手工指定该接口的 Cost 值,手工指定的优先于自动计算的值。OSPF 计算的 Cost,同样是和接口带宽成反比,带宽越高,Cost 值越小。

weixin_43981813的博客 1130

高并发核心技术 - 库存

高并发核心技术 - 订单与库存 问题: 一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品。如何保证库存在高并发的场景下是安全的。 1.不多发 2.不少发 下单涉及的一些步骤 1.下单 2.下单同时预占库存 3.支付 4.支付成功真正减扣库存 5.取消订单 6.回退预占库存 什么时候进行预占库存 方案一:...

0-1的专栏 276

订单相关场景

https://www.youkuaiyun.com/tags/NtTaYg0sODYwNzktYmxvZwO0O0OO0O0O.html https://blog.youkuaiyun.com/D812359/article/details/120797954以上三种扣库存方式是电商平台最常见的方式,其中第三种方式运用较多,每种方式都有自己使用的场景。商品库存数量较为敏感的场景,比如秒杀、抢购等建议使用下单减库存的方式,大部分正常买家都是想直接购买超优惠的商品。如果采用付款减库存的方式,可能会出现商品超卖的情况。比如商家设置秒杀

Linging_24的博客 1282

java redis库存的减少_高并发订单库存系统如何实现?让我们来看看Redis如何解决高并发下订单库存的高可用性!...

一、高并发下的问题A、B两个商品各有若干库存,如何在高并发下保证商品库存的安全性?1)库存是否存在多扣?2)库存是否存在少扣?3)扣库存的时候是否存在死锁?二、 下单的步骤(1)下单(2)下单同时预占库存(3)支付(4)发货真正减扣库存(5)取消订单(6)回退预占库存三、 重复下单问题(1)用户点击过快,重复提交两次(2)网络延时,用户刷新或者点击下单重复提交(3)网络框架重复请求,某些网络框架,...

weixin_28811757的博客 1075

商城 锁定库存问题

文章目录背景什么时候进行预占库存?重复下单问题如何安全的减扣库存订单时效问题,订单取消等 背景 问题:一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品。如何保证库存在高并发的场景下是安全的。 1.不多发 2.不少发 下单涉及的一些步骤: 1.下单 2.下单同时预占库存 3.支付 4.支付成功真正减扣库存 5.取消订单 6.回退预占库存 什么时候进行预占库存? 方案一:加入购物车的时候去预占库存。 方案二:下单的时候去预占库存。 方案三:支付的时候去预占库存

m0_45406092的博客 5342

分布式锁防止订单重复提交_高并发场景下的订单和库存处理方案!收藏这个就够了!...

来源:https://juejin.im/post/5f0f03756fb9a07e9950adad作者:前程有光前言之前一直有小伙伴私信我问我高并发场景下的订单和库存处理方案,我最近也是因为加班的原因比较忙,就一直没来得及回复。今天好不容易闲了下来想了想不如写篇文章把这些都列出来的,让大家都能学习到,说一千道一万都不如满满的干货来的实在,干货都下面了!介绍前提:分布式系统,高并发场景 ...

weixin_36453829的博客 1355

redis rua解决库存问题_如何解决高并发下的库存安全问题,没你想得那么复杂(附源码)...

一、 问题不知道大家该开发中有没有遇到这样的一个问题,在电影院购票或者去网上买东西的时候,比方说当年哪吒大电影出来的时候,那抢票相当火爆啊,一票难求,那购票系统的后台是如何保证观众能买到自己喜欢的票同时不用担心会被别人抢走呢?还有一个典型的例子,每年双十一的疯狂的时候,准时抢购的时候,同一时间内会有大量的订单涌入,先不说负载的事情,那么后面再说,我们来说一下,他是如何保证库存安全的呢?不会出现已经...

weixin_39531594的博客 152
下一篇: 分布式事务Seata
南秋同学
博客等级 码龄7年 65粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值