并发下的库存如何扣?

Redis 实现高并发库存扣减方案 redis,库存 阅读详情

并发下的库存如何扣?

背景

业务反馈,项目出现库存超卖/负值现象。

原因

    //简易demo
    $conn = mysqli_connect('localhost','root','123456','shop') or die('数据库连接失败');
    $conn->query("SET NAMES 'UTF8'");
    $query = "SELECT num FROM stock where id = 1"; 
    $rs = $conn->query($query);
	$row = $rs-> fetch_array();
	
	$num = $row['num'];
	$reduce = 1;
	$update = 'update stock set num = num - '.$reduce.' where id = 1';
	if($conn->query($update)){
	    echo 'success';
	}else{
	    //重试
	    $conn->query($update)
	};

假设库存为5,用户一次买了1个,于是库存扣减为4,如果更新失败则重新设置,看似好像没问题。

问题1

库存扣为负值

	$num = $row['num'];
	$reduce = 1;
	if($num >= $reduce){
        $update = 'update stock set num = num - '.$reduce.' where id = 1';
        if($conn->query($update)){
            echo 'success';
        }else{
            //重试
            $conn->query($update)
        }
	}

这样就不会出现库存为负值

问题2

非幂等操作,库存重复扣得问题(库存为5个,用户想买2个,因为并发&重试,实际扣了4个库存)

此时,我们必须知道,“set num=num-$reduce”扣减操作是个“非幂等操作”,即每次sql执行得到的结果不一样,实际我们需要的是用户重试多次得到的应该是同样的结果,这却是个“幂等操作”,所以换个思路,我们将“非幂等”的“扣减操作”改为“幂等”的“设置库存操作”

	$num = $row['num'];
	$reduce = 1;
	$newNum = $num - $reduce;
	if($newNum >= 0){
        $update = 'update stock set num = '.$newNum.' where id = 1';
        if($conn->query($update)){
            echo 'success';
        }else{
            //重试
            $conn->query($update)
        }
	}
  

问题3

并发问题

一共5个库存

A买了3,库存设置为2

B买了2个库存,库存要设置为3

这两个设置库存并发执行,库存会先变成2,再变成3,导致数据不一致(实际卖出了5件商品,但库存只扣减了2,最后一次设置库存会覆盖和掩盖前一次并发操作)

其根本原因是,设置操作发生的时候,没有检查库存与查询出来的库存有没有变化,理论上:
库存为5时,A的库存设置才能成功
库存为5时,B的库存设置才能成功
实际执行的时候:
库存为5,A的set stock 2确实应该成功
库存变为2了,B的set stock 3应该失败掉

修改 (CAS原理)

	$num = $row['num'];
	$reduce = 1;
	$newNum = $num - $reduce;
	if($newNum >= 0){
        $update = 'update stock set num = '.$newNum.' where id = 1 and num = '.$num;
        if($conn->query($update)){
            echo 'success';
        }else{
            //重试
            $conn->query($update)
        }
	}

问题4 CAS引发的ABA问题

ABA问题
并发1(上):获取出数据的初始值是A,后续计划实施CAS乐观锁,期望数据仍是A的时候,修改才能成功
并发2:将数据修改成B
并发3:将数据修改回A
并发1(下):CAS乐观锁,检测发现初始值还是A,进行数据修改
ABA在多数库存情况下不会引发业务问题,但是少数的情况下会出现错误。
所以,周全的办法是也要解决ABA问题
ABA本质上是“仅比对值”造成的问题,所以我们可以对库存加上一个版本号来解决该问题,每修改一次数据则版本号变更一次

update stock set num=$new_num, version=$new_version where sid=$sid and version=$version_old
	$num = $row['num'];
        $oldVersion = $row['version '];
        $newVersion = $oldVersion++;
	$reduce = 1;
	$newNum = $num - $reduce;
	if($newNum >= 0){
        $update = 'update stock set num = '.$newNum.',version='.newVersion .' where id = 1 and version= '.$oldVersion ;
        if($conn->query($update)){
            echo 'success';
        }else{
            //重试
            $conn->query($update)
        }
	}

总结

高并发下库存应如下优化

  • “设置库存”保证幂等性
  • “设置库存”,需要加上原有库存的比较,才允许设置成功,能解决高并发下库存扣减的一致性问题
  • CAS引发的ABA问题采用version比对解决

请关注我的订阅号

订阅号.png

Java面试场景题实战:从并发扣库存到OOM排查 在Java技术栈中,并发编程与系统设计能力是衡量开发者工程水平的核心指标。无论是并发扣库存、订单超时关闭,还是接口幂等性保障,其本质都要求开发者理解线程安全、原子操作与最终一致性等底层原理。掌握这些原理,不仅能在高并发场景下做出合理的技术选型,如基于Redis Lua脚本优化库存扣减、利用延迟队列处理超时订单,还能在系统故障时快速定位问题。从数据库乐观锁到MQTT设备接入,从JVM堆转储分析到接口幂等设计,这些技术价值贯穿于日常开发与线上运维的各个环节。围绕Java面试场景题,梳理高频场景题的答题思路、可运 阅读详情

相关推荐

微信小程序点餐系统实战:订单状态机与并发扣库存详解

微信小程序作为轻量级应用形态,已成为餐饮数字化的重要载体。而点餐系统的核心不仅是前端交互,更涉及后端服务、数据库设计和并发一致性等工程问题。Spring Boot结合MyBatis Plus提供了高效的后端开发框架,MySQL作为持久层保证了数据可靠存储。在订单处理链路中,状态机设计用于规范订单合法跳转,乐观锁机制则能有效防止库存超卖,这些技术点正是系统稳定性的关键。本文以校园餐厅点餐小程序为例,梳理从数据库表设计、小程序端交互到管理后台的完整实现路径,并分享模拟支付、幂等处理、订阅消息等实战细节,为毕业设

weixin_30628077的博客 842

高并发场景下的库存管理,理论与实战能否兼得?

本篇文章,是一篇实战后续篇,是基于之前我发了一篇关于如何构建高并发系统文章的延伸:

京东科技开发者 670

库存扣减——如何处理扣多了

在业务复杂,数据量大,并发量大的情况下,库存扣减容易引发数据的不一致,常见的优化方案有两个: • 调用“设置库存”接口,能够保证数据的幂等性 • 在实现“设置库存”接口时,需要加上原有库存的比较,才允许设置成功,能解决高并发下库存扣减的一致性问题

高并发场景的库存扣减方案

支持高并发场景高效库存扣减方案

qq_17509371的博客 2311

SAP License:SAP会计凭证抬头的字段状态控制

FI模块的同事一般都知道在FI中有个字段状态变式,可以控制在凭证输入时哪些字段是必输、哪些可选哪些隐藏,但这只对凭证行项目中有效,你是否想过对于凭证抬头的字段是哪控制呢? 在中国,会计附件上都要带一个附件张数字段,但SAP的默认配置中没有这一字段,并非SAP没有设置此字段,而是我们没有配置这一字段。如果需要在凭证输入时放出分支号(BRNCH)、附件页数(NUMPG)等字段,在个人参数文件中加入参数CSF,参数值AR,即可。如下图: 实际上,这是对凭证国家的一个设置,在SAP中,配置了AR这个国家..

SAP权限管控|SAP用户权限管理|SAP权限合规检查|SAP全日志管理 2221

Simulink Test Sequence实战:5步搞定复杂逻辑测试(附Excel模板)

本文详细介绍了如何利用Simulink Test Sequence模块高效完成复杂逻辑测试。通过对比传统Excel方法的不足,阐述了Test Sequence以流程图和自然语言描述测试场景的优势,并提供了从环境搭建、逻辑构建到与Test Manager集成、利用Excel模板进行数据驱动的完整5步实战指南,帮助工程师将复杂的状态机或逻辑流测试从繁琐的‘体力活’转变为高效的‘技术活’。

snow3的博客 249

高并发业务下的库存扣减方案

编程严选网专注分享软件开发全生态相关技术文章视频教程资源、热点资讯等,全站资源免费学习,快来看看吧~编程严选】星球。

竹林幽深 314

别再死记硬背公式了!用Unity ShaderGraph从零实现一个皮肤SSS效果(附完整节点图)

本文详细介绍了如何利用Unity ShaderGraph零代码实现皮肤次表面散射(SSS)效果,包括背光透射(BTDF)和表面散射(BSSRDF)的核心原理与节点构建方法。通过可视化工具,技术美术师和Shader初学者可以直观理解光线在皮肤组织中的散射行为,快速创建真实的皮肤材质效果,适用于游戏角色渲染等场景。

weixin_30838873的博客 590

ThreadLocal存储数据库Connection的几种模式

ThreadLocal存储数据库Connection

qq_20671779的博客 789

ARTIX-7 GTP 3G-SDI 工程构建与调试实战

本文详细介绍了基于ARTIX-7 FPGA和GTP收发器的3G-SDI工程构建与调试实战。从基础概念解析到Vivado工程创建、GTP IP核配置、SDI IP核集成,再到系统集成与时钟域处理,提供了全面的技术指导。文章还分享了调试技巧、常见问题排查方法以及性能验证步骤,帮助开发者快速掌握3G-SDI视频传输技术的实现与优化。

weixin_30443813的博客 256

从HPPC测试到Simulink仿真:锂电池二阶RC模型参数辨识完整流程

本文详细介绍了从HPPC测试到Simulink仿真的锂电池二阶RC模型参数辨识完整流程。通过HPPC测试获取实验数据,利用Simulink的Parameter Estimation工具进行参数辨识和模型验证,为BMS算法开发提供精确的电池模型。文章涵盖测试设计、数据预处理、模型搭建及工程应用等关键步骤,助力新能源电池研发。

whisky的博客 683

订单取消、扣库存以及并发扣库存

1.取消订单的操作是怎么实现的? 取消...

m0_51697147的博客 231

blenderproc 制作位姿估计数据集

blenderproc 制作位姿估计数据集 准备工作 1.首先需要去下载blenderproc的源码blenderproc,按照作者的readme文件进行编译。 2.其次需要下载bop_toolkit源码,链接如下bop_toolkit 3.说明:blenderproc主要用来生成数据,包括depth,rgb,位姿标签文件(scene_gt.json),bop_toolkit主要用来生成mask和mask_visib,scene_gt_info.json,用于判断物体的可见区域比例,如果遮挡太多考虑去掉。做

qq_43814359的博客 5697

使用MySQL乐观锁解决电商扣库存并发问题

你知道的越多,不知道的就越多,业余的像一棵小草!你来,我们一起精进!你不来,我和你的竞争对手一起精进!编辑:业余草来源:cnblogs.com/laoyeye/p/8097684.htm...

xmt1139057136的专栏 1844

华为OD机考双机位C卷 - 区间交集(Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 区间交集

算法大师! 1136

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

秒杀系统,扣库存,高并发场景下订单和扣库存讲解

前言 之前一直有小伙伴私信我问我高并发场景下的订单和库存处理方案,我最近也是因为加班的原因比较忙,就一直没来得及回复。今天好不容易闲了下来想了想不如写篇文章把这些都列出来的,让大家都能学习到,说一千道一万都不如满满的干货来的实在,干货都下面了! 介绍 前提:分布式系统,高并发场景 商品A只有100库存,现在有1000或者更多的用户购买。如何保证库存在高并发的场景下是安全的。 预期结果:1.不超卖 2.不少卖 3.下单响应快 4.用户体验好 下单思路: 下单时生成订单,减库存,同时记录库存流水,在这

yjl33的专栏 3946

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

GO微服务中分别用乐观锁,悲观锁,redis分布式锁解决购物平台并发扣库存问题

在购物平台中,扣库存是一个非常关键的操作,涉及到多个并发的操作,比如多个用户同时购买同一商品,或者同时购买多个商品等。在这种情况下,如果不加锁,可能会导致数据不一致、库存错误等问题。

weixin_63603830的博客 836

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

浅谈并发扣库存

秒杀的场景有很多,比如:抢购、抢票、抢红包等等。总之,就是在极短时间内有大量的请求。 我们都知道,这种系统设计的大方向就是限流,即通过层层过滤,最终只让相对较少的请求进入到核心业务处理层。 这里不谈秒杀设计,不谈使用队列等使请求串行化,就谈下怎么用锁来保证数据正确,就是已经到减库存那一步了,在这一步中如果保证不超卖。 用队列的话,可以是Java自动的队列,也可以用Redis的LPUSH RP...

BrianWey的博客 766

Java架构直通车——订单扣库存问题

文章目录场景描述扣库存问题不推荐的方案:扣库存问题解决方案推荐:如何验证 场景描述 无论是日常工作中,还是面试问题中,并发扣库存都是一个很常见的场景,正好业务里有这样的场景,可以对这类问题做一下总结。 举例说明两个比较典型的扣库存场景: 产品1:线上招募人员的产品,招募是有人数限制的,每招募成功1人,扣减库存1,直到库存为0,自动停止招募。 产品2:用户秒杀产品,用户在同一个时间点,同时抢一...

No_Game_No_Life_的博客 1768

电商下单扣库存并发问题

电商扣库存:脏读 → 靠隔离级别(MySQL 默认即可)超卖/丢失更新 → 靠原子 SQL / 悲观锁 / 乐观锁秒杀 → Redis + MQ + 数据库兜底最实用写法:影响行数 = 0 → 库存不足。

weixin_46228563的博客 98

KES数据库事务一致性与并发控制实践:下单扣库存场景

本文通过一个真实的下单扣库存业务场景,演示了KES数据库中事务的使用方法。文章首先介绍了事务的ACID特性,强调在订单系统中保持数据一致性的重要性。然后详细展示了事务的完整流程:使用BEGIN开启事务,通过FOR UPDATE锁定商品库存行防止并发修改,插入订单主表和明细记录,更新库存数量,最后用COMMIT提交成功操作。文章还特别指出要检查UPDATE语句的返回值,确保库存扣减成功。整个流程确保了订单生成和库存扣减要么全部成功,要么全部回滚,有效避免了数据不一致问题。通过这个案例,读者可以理解事务

编程世界如山海,探索不止。 2万+

防止并发超扣库存

在事务中给update的sql加限定条件,如果库存不足,就让sql执行失败。 文章Mysql在高并发情况下,防止库存超卖而小于0的解决方案 高并发,如何批量生成自增编号? 也可以用事务,先查询出来,然后直接让标识增加多个数,然后update的条件加上查出来的值,这里需要使用事务。 转载于:https://www.cnblogs.com/Tpf386/p/8066075.ht...

weixin_30408739的博客 295

一层一层实现高并发扣库存的问题

package jedis; import redis.clients.jedis.Jedis; import redis.clients.jedis.params.SetParams; import java.security.Key; import java.util.UUID; /** * @author mawt * @description * @date 2020/8/7 */ public class TestJedis { private static Jedis .

淋雨西河的博客 357

mysql 扣库存_使用MySQL悲观锁解决电商扣库存并发问题

使用MySQL悲观锁解决并发问题昨天写了乐观锁《使用MySQL乐观锁解决电商扣库存并发问题》,有人提出想看悲观锁,所以今天我们就说一说如何抗悲观锁解决并发问题:悲观锁介绍(百科):悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的...

weixin_39618956的博客 281
上一篇: 开源-laravel-react-hexo(next)主题的博客系统
下一篇: 大数据高并发下表如何扩展字段?
码哥说
博客等级 码龄8年 5645粉丝 172原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码哥说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值