`
javashop
  • 浏览: 42845 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

电商系统中库存的存储于扣减

阅读更多

 

电商系统中,sku的库存是核心单元,本文以Javashop电商系统为例,说明库存的存储于扣减思路

商品库存更新库存添加和扣减,当用户执行下单操作时 发送消息给MQ, consumer执行扣减库存操作。商家端有单独接口维护库存。

库存更新主要是操作商品Sku库存信息。SKU是物理上不可分割的最小存货单元。也就是说一款商品,可以根据SKU来确定具体的货物存量。对应es_goods_sku表

商品库存和商品sku库存

商品的可用库存和实际库存(actual 实际库存)(enable 可用库存)

在redis中的键为库存前缀_库存名称_商品id

{stock}{GOODS_STOCK}_actual_65

{stock}{GOODS_STOCK}_enable_127

sku的实际库存和可用库存

在redis中的键为库存前缀_库存名称_商品skuid

{stock}{SKU_STOCK}_actual_1320633609858965506

{stock}{SKU_STOCK}_enable_1310759679300034562

商家端更新商品库存,通GoodsQuantityManager.updateSkuQuantity() 将sku和商品信息更新到redis和数据库 如果lua脚本执行成功,判断javashopConfig配置中是否开启缓冲池,如果开启则更新缓冲区库存,未开启则同步数据到数据库库存。

首先查出缓存商品信息 包括商品信息 和商品sku信息

@PutMapping
public void updateQuantity(@ApiIgnore@Valid @RequestBody List<GoodsSkuQuantityVO>  skuQuantityList, @PathVariable("goods_id")Long goodsId)  {

   CacheGoods goods = goodsQueryManager.getFromCache(goodsId);

   Seller seller = UserContext.getSeller();
   if(goods == null || !goods.getSellerId().equals(seller.getSellerId())){
      throw new ServiceException(GoodsErrorCode.E307.code(), "没有操作权限");
   }

   // 原有的sku集合
   List<GoodsSkuVO> skuList = goods.getSkuList();
   Map<Long,GoodsSkuVO> skuMap = new HashMap<>(skuList.size());
   for(GoodsSkuVO sku : skuList){
      skuMap.put(sku.getSkuId(), sku);
   }

 

校验库存 判断商品库存数量,是否具有sku信息和待发货数量 代发货数量必须小于可用库存数量,实际库存是设置后固定,可用库存是当前剩余库存量

//要更新的库存列表
List<GoodsQuantityVO> stockList = new ArrayList<>();

for (GoodsSkuQuantityVO quantity : skuQuantityList) {

   if (quantity.getQuantityCount() == null || quantity.getQuantityCount() < 0 ) {
      throw new ServiceException(GoodsErrorCode.E307.code(), "sku总库存不能为空或负数");
   }

   GoodsSkuVO sku = skuMap.get(quantity.getSkuId());
   if(sku == null){
      throw new ServiceException(GoodsErrorCode.E307.code(), "商品sku不存在");
   }
   //待发货数
   Integer waitRogCount = sku.getQuantity()-sku.getEnableQuantity();
   //判断库存是否小于待发货数
   if (quantity.getQuantityCount()<waitRogCount) {
      throw new ServiceException(GoodsErrorCode.E307.code(), "sku库存数不能小于待发货数");
   }

 实际库存和可用库存 库存

//实际库存
   GoodsQuantityVO actualQuantityVo = new GoodsQuantityVO();
   //用传递的数量-现有的,就是变化的,如传递的是2000,原来是200,则就+1800,如果传递的是100,原来是200则就是-100
   int stockNum = quantity.getQuantityCount() -sku.getQuantity();
   actualQuantityVo.setQuantity(stockNum );
   actualQuantityVo.setGoodsId(goodsId);
   actualQuantityVo.setQuantityType(QuantityType.actual);
   actualQuantityVo.setSkuId(quantity.getSkuId());

   stockList.add(actualQuantityVo);

   //clone 一个quantity vo 设置为更新可用库存
   try {
      GoodsQuantityVO enableVo =(GoodsQuantityVO)    actualQuantityVo.clone();
      enableVo.setQuantityType(QuantityType.enable);
      stockList.add(enableVo);
   } catch (CloneNotSupportedException e) {
      throw new ServiceException(GoodsErrorCode.E307.code(), "goodsQuantityVo clone error");
   }

}

 更新库存 数据库和缓存中都需要更新,当开启缓冲池并且缓冲池中数据已经饱和 则同步更新数据库,如果未开启缓冲池,则实时同步商品数据库中的库存数据

//更新库存
this.goodsQuantityManager.updateSkuQuantity(stockList);

//如果商品库存缓冲池开启了,那么需要立即同步数据库的商品库存,以保证商品库存显示正常
if (javashopConfig.isStock()) {
   //立即同步数据库的库存
   goodsQuantityManager.syncDataBase();
}

 更新sku库存采用redis+lua脚本 利用redis原子性避免超卖问题

public Boolean updateSkuQuantity(List<GoodsQuantityVO> goodsQuantityList) {

    List<Long> skuIdList = new ArrayList();
    List<Long> goodsIdList = new ArrayList();

    List keys = new ArrayList<>();
    List values = new ArrayList<>();

    for (GoodsQuantityVO quantity : goodsQuantityList) {

        Assert.notNull(quantity.getGoodsId(), "goods id must not be null");
        Assert.notNull(quantity.getSkuId(), "sku id must not be null");
        Assert.notNull(quantity.getQuantity(), "quantity id must not be null");
        Assert.notNull(quantity.getQuantityType(), "Type must not be null");


        //sku库存
        if (QuantityType.enable.equals(quantity.getQuantityType())) {
            keys.add(StockCacheKeyUtil.skuEnableKey(quantity.getSkuId()));
        } else if (QuantityType.actual.equals(quantity.getQuantityType())) {
            keys.add(StockCacheKeyUtil.skuActualKey(quantity.getSkuId()));
        }
        values.add("" + quantity.getQuantity());

        //goods库存key
        if (QuantityType.enable.equals(quantity.getQuantityType())) {
            keys.add(StockCacheKeyUtil.goodsEnableKey(quantity.getGoodsId()));
        } else if (QuantityType.actual.equals(quantity.getQuantityType())) {
            keys.add(StockCacheKeyUtil.goodsActualKey(quantity.getGoodsId()));
        }
        values.add("" + quantity.getQuantity());


        skuIdList.add(quantity.getSkuId());
        goodsIdList.add(quantity.getGoodsId());
    }

    RedisScript<Boolean> redisScript = getRedisScript();
    Boolean result = stringRedisTemplate.execute(redisScript, keys, values.toArray());

    logger.debug("更新库存:");
    logger.debug(goodsQuantityList.toString());
    logger.debug("更新结果:" + result);

    //如果lua脚本执行成功则记录缓冲区
    if (result) {

        //判断配置文件中设置的商品库存缓冲池是否开启
        if (javashopConfig.isStock()) {

            //是否需要同步数据库
            boolean needSync = getSkuPool().oneTime(skuIdList);
            getGoodsPool().oneTime(goodsIdList);

            logger.debug("是否需要同步数据库:" + needSync);
            logger.debug(getSkuPool().toString());

            //如果开启了缓冲池,并且缓冲区已经饱和,则同步数据库
            if (needSync) {
                syncDataBase();
            }
        } else {
            //如果未开启缓冲池,则实时同步商品数据库中的库存数据
            syncDataBase(skuIdList, goodsIdList);
        }

    }


    return result;
}

 

 
 
 
分享到:
评论

相关推荐

    电商系统SpringBoot2.1.3、MyBatis3.4.6、Elasticsearch6.2.2、RabbitMQ

    在高并发的电商场景下,RabbitMQ用于解耦业务模块间的通信,通过消息中间件实现异步处理,如订单生成后发送消息到库存系统进行库存扣减,保证了系统的高可用性和稳定性。 这四个组件在电商系统中的协作至关重要。...

    SSM电商平台后台管理系统.rar

    这个系统主要用于电商行业的后台管理,涵盖了商品管理、订单处理、用户管理、库存控制、营销活动等多种功能,旨在提高电商运营效率,优化业务流程。 1. **Spring框架**:Spring是Java开发中的核心框架,它提供了...

    电商-数据库详细设计说明书

    6. **事务处理与并发控制**:电商系统中,如订单支付、库存扣减等操作需要保证原子性,因此需要设计合适的事务策略,同时避免死锁。 7. **安全与备份**:数据库需要有强大的安全措施,防止数据泄露。定期备份是必要...

    基于springBoot的一个分布式电商系统.zip

    分布式电商系统通常涉及到多个模块,如用户管理、商品展示、订单处理、库存管理、支付接口等,每个模块可能作为一个独立的服务运行,通过API进行通信。 【知识点详解】: 1. **SpringBoot**:SpringBoot是Spring...

    PHP实例开发源码—商淘连锁店管理电商系统PHP版.zip

    3. **数据库管理**:电商系统通常使用MySQL等关系型数据库存储数据,如商品信息、用户信息、订单状态等。开发者需要熟练掌握SQL查询语言,以实现数据的增删改查和复杂查询。 4. **MVC模式**:模型-视图-控制器(MVC...

    电子政务-基于分布式事务协调与控制的电商系统.zip

    例如,当一个用户下单购买商品时,这可能涉及到用户账户余额的扣减、库存的减少、物流信息的更新等多个子事务,这些子事务分布在不同的数据库或服务中。因此,确保这些子事务的一致性是系统稳定运行的关键。 分布式...

    【源码版】基于SpringMVC的电商高并发秒杀系统设计思路

    3. **分布式事务**:在秒杀过程中,可能会涉及到库存的扣减、用户订单的创建等多个操作,这些操作需要保证原子性和一致性。SpringMVC框架下的分布式事务管理可以借助Spring的Transaction API和分布式事务解决方案...

    基于SSM的电商平台

    这个"基于SSM的电商平台"项目提供了完整的源码,让我们来深入探讨一下SSM框架在电商系统中的应用及其相关知识点。 首先,Spring框架作为基础,它提供依赖注入(DI)和面向切面编程(AOP)功能,使得代码更加模块化...

    12. 电商Ego-订单系统实现.zip

    在电商行业中,订单系统是核心组成部分之一,它负责处理从用户下单到订单完成的整个流程。本电商Ego-订单系统的实现主要基于Java技术栈,结合了dobux框架,为电商平台提供稳定、高效的订单处理能力。以下是根据标题...

    mall学习教程,架构、业务、技术要点全方位解析。mall项目(50k+star)是一套电商系统.zip

    3. 消息队列:RabbitMQ或Kafka实现异步处理,如订单创建后的库存扣减、发送通知等,提高系统吞吐量。 4. 安全机制:JWT(JSON Web Tokens)实现用户身份验证,防止CSRF攻击;HTTPS保障通信安全。 5. 高并发处理:...

    java电商秒杀实战数据库.rar

    在Java电商秒杀实战数据库中,我们探讨的核心技术与实践主要围绕着如何构建高效、稳定且可扩展的秒杀系统。秒杀系统是电子商务中一个关键的组成部分,它考验着平台的技术实力,需要处理瞬间高并发请求,确保数据的...

    Java开发的仿得物电商后台系统源码.zip

    - **RabbitMQ或Kafka**:用于异步处理,解耦各个服务,如订单创建后的库存扣减、发送通知等。 7. **Docker与Kubernetes**: - **Docker**:容器化技术,用于打包和部署应用程序。 - **Kubernetes**:容器编排...

    PHP实例开发源码-进云智慧电商客源码包.zip

    2. **订单处理**:订单系统是电商流程的核心,涉及到用户下单、支付、库存扣减、物流跟踪等环节。源码可能包含订单状态管理、支付接口集成(如支付宝、微信支付)、订单查询与取消等逻辑。这部分源码将揭示PHP如何...

    千亿级电商秒杀解决方案专题

    秒杀过程中,商品库存的扣减是一个关键环节,需要保证强一致性。可以采用乐观锁或分布式事务(如2PC、TCC、Saga)来解决跨服务的数据一致性问题。在分布式环境下,CAP理论和BASE理论是指导设计的重要原则。 三、限...

    谷粒商城 微服务分布式 电商项目 2020 完整代码

    【谷粒商城】是一个以微服务架构为基础的分布式电商系统,该项目在2020年进行了全面更新,提供了完整的源代码,旨在帮助开发者理解和实践微服务在实际业务场景中的应用。下面将详细介绍该项目中涉及的主要知识点。 ...

    基于sprignboot的电商书城源码.zip

    5. 分布式事务处理:电商系统中,如订单支付、库存扣减等操作需要原子性,可能涉及到分布式事务。SpringBoot可以通过Atomikos、Seata等分布式事务管理器实现分布式事务的协调。 6. 微服务架构:随着业务复杂度增加...

    电商平台软件架构.pdf

    1. **中台服务**:中台是现代电商系统的核心,它将通用的业务能力进行抽象和复用,以提高开发效率和系统稳定性。订单服务、图片服务、监控服务、同步服务、库存服务、产品服务、评论服务、积分/代金券/卡/余额服务、...

    android电商开发购买多属性选择

    在Android电商开发中,商品的多属性选择(SKU选择)是一项关键功能,它涉及到商品的库存管理、购物车逻辑以及订单处理等多个环节。本篇将深入探讨这一主题,旨在为开发者提供详尽的理解和实现策略。 一、商品与SKU...

    电商数据库设计.pdf

    在电商行业中,数据库设计是构建高效、稳定且可扩展的电商...以上是电商数据库设计的基本框架,实际设计过程中还需结合业务需求、技术选型、性能指标等因素进行详细规划和调整,确保数据库能够支撑电商系统的高效运行。

    Redis开发电商网站.rar

    8. **商品库存扣减**:利用Redis的事务或lua脚本实现库存的原子性扣减,保证并发环境下的数据一致性。 9. **购物车服务**:Redis的Set或Hash数据结构适合作为购物车的存储,快速添加、修改、删除商品。 10. **推荐...

Global site tag (gtag.js) - Google Analytics