(一)库存超卖案例实战——库存超卖现象的产生及其解决方案概述

2023-10-20 20:12

本文主要是介绍(一)库存超卖案例实战——库存超卖现象的产生及其解决方案概述,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

本节内容我们主要介绍一下web应用中常见的一类问题——产品“超卖”问题,通过一个springboot项目案例完成超卖现象的演示,并针对不同的应用场景下,提供这一类问题的解决方案,关于更详细的解决方案案例实战内容,请关注作者后期的博客内容。

正文

①创建一个商品库存表,用于商品库存的存储

CREATE TABLE `wms_stock` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',`stock_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '仓库编号',`product_code` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '产品',`stock_quantity` int DEFAULT NULL COMMENT '库存数量',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='库存';

②商品库存表中增加一条库存数据用于库存数据的测试

INSERT INTO `wms_stock` (`id`, `stock_code`, `product_code`, `stock_quantity`) VALUES (1, 'A1000', 'P2000', 10000);

③ springboot项目中创建一个WmsStockController类,实现一个扣减库存的请求

package com.ht.atp.plat.controller;import com.ht.atp.plat.common.Result;
import com.ht.atp.plat.service.WmsStockService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** <p>* 库存 前端控制器* </p>*/
@Api(tags = {"库存管理"})
@RestController
@RequestMapping("/wms/stock")
public class WmsStockController {@Autowiredprivate WmsStockService wmsStockService;@ApiOperation("检查并扣减库存")@GetMapping("checkAndReduceStock")public Result checkAndReduceStock() {wmsStockService.checkAndReduceStock();return Result.success();}}

 ④ springboot项目中创建一个WmsStockService接口类,实现一个扣减库存的业务接口

package com.ht.atp.plat.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.ht.atp.plat.entity.WmsStock;/*** <p>* 库存 服务类* </p>*/
public interface WmsStockService extends IService<WmsStock> {/*** 检查并扣减库存*/void checkAndReduceStock();}

 ⑤ springboot项目中创建一个WmsStockServiceImpl实现类,实现一个扣减库存的业务实现

package com.ht.atp.plat.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.atp.plat.entity.WmsStock;
import com.ht.atp.plat.mapper.WmsStockMapper;
import com.ht.atp.plat.service.WmsStockService;
import org.springframework.stereotype.Service;/*** <p>* 库存 服务实现类* </p>*/
@Service
public class WmsStockServiceImpl extends ServiceImpl<WmsStockMapper, WmsStock> implements WmsStockService {@Overridepublic void checkAndReduceStock() {// 查询库存WmsStock wmsStock = baseMapper.selectById(1L);// 验证库存大于0再扣减库存if (wmsStock != null && wmsStock.getStockQuantity() > 0) {wmsStock.setStockQuantity(wmsStock.getStockQuantity() - 1);baseMapper.updateById(wmsStock);}}
}

 ⑥启动测试项目,通过浏览器访问扣减库存接口,库存由10000正常扣减为9999

⑦将扣减的库存恢复为10000,使用jmeter压测工具并发测试。添加一个线程组:并发100循环100次,即10000次请求

⑧给线程组添加HTTP Request请求

⑨添加扣减库存接口配置

⑩添加压测报告

 ⑪开始使用jmeter压测

测试结果:请求总数10000次,平均请求时间130ms,中位数(50%)请求是在83ms内完成的,错误率0%,每秒钟平均吞吐量754次。库存还没有扣减的为9808。此时就产生了超卖现象。实际库存应该为0。

⑫对于该并发问题我们使用jvm的synchronized本地加锁或者使用ReentrantLock加锁

⑬ 恢复库存数据为10000,再次使用jmeter工具压测

测试结果:请求总数10000次,平均请求时间332ms,中位数(50%)请求是在304ms内完成的,错误率0%,每秒钟平均吞吐量296次。库存扣减为0。本地加锁确实解决了并发的问题。可以从测试结果中发现,本地加锁确实可以解决“超卖的问题”,同时也会降低接口访问请求的吞吐量,由于加锁的原因。

⑭本地加锁存在的问题

对于单应用而言,本地加锁确实能够解决并发访问的问题。我们知道本地锁只能对本jvm虚拟机内是有效的,对于分布式多服务应用而言,为了高可用高并发往往会将单个应用部署为多个服务节点,这个时候,本地锁只能对本服务有效,依然会有并发的问题。那么对于多服务的应用该如何解决并发问题呢,这就要用到分布式锁了,关于分布式锁的相关内容实战,请关注我的后期的内容。

结语

对于“超卖”这一类问题,我们只能通过加锁的方式控制并发访问。在实际开发过程中,对于单体应用场景而言,我们可以使用本地锁实现并发访问控制,对于分布式微服务应用的场景中,我们可以使用分布式锁,控制并发访问。在后续的内容中,我们通过具体的技术解决方案,实现并发问题的解决。

这篇关于(一)库存超卖案例实战——库存超卖现象的产生及其解决方案概述的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/249458

相关文章

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

六个案例搞懂mysql间隙锁

《六个案例搞懂mysql间隙锁》MySQL中的间隙是指索引中两个索引键之间的空间,间隙锁用于防止范围查询期间的幻读,本文主要介绍了六个案例搞懂mysql间隙锁,具有一定的参考价值,感兴趣的可以了解一下... 目录概念解释间隙锁详解间隙锁触发条件间隙锁加锁规则案例演示案例一:唯一索引等值锁定存在的数据案例二:

Java死锁问题解决方案及示例详解

《Java死锁问题解决方案及示例详解》死锁是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态,本文给大家详细介绍了Java死锁问题解决方案详解及实践样例,需要的朋友可以参考下... 目录1、简述死锁的四个必要条件:2、死锁示例代码3、如何检测死锁?3.1 使用 jstack3.2

html 滚动条滚动过快会留下边框线的解决方案

《html滚动条滚动过快会留下边框线的解决方案》:本文主要介绍了html滚动条滚动过快会留下边框线的解决方案,解决方法很简单,详细内容请阅读本文,希望能对你有所帮助... 滚动条滚动过快时,会留下边框线但其实大部分时候是这样的,没有多出边框线的滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

MySQL版本问题导致项目无法启动问题的解决方案

《MySQL版本问题导致项目无法启动问题的解决方案》本文记录了一次因MySQL版本不一致导致项目启动失败的经历,详细解析了连接错误的原因,并提供了两种解决方案:调整连接字符串禁用SSL或统一MySQL... 目录本地项目启动报错报错原因:解决方案第一个:第二种:容器启动mysql的坑两种修改时区的方法:本地

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas