java电商mysql中存储什么_电商系统中库存的存储于扣减

本文探讨了电商系统中库存管理的核心——SKU库存,详细阐述了库存的存储、更新和扣减流程。在用户下单时,通过MQ发送消息进行库存扣减,同时商家端有接口维护库存。库存更新主要涉及商品Sku的实际库存和可用库存,使用Redis存储并借助Lua脚本确保原子性,防止超卖。当库存更新成功后,根据配置是否开启缓冲池决定实时同步数据库或等待缓冲区饱和后再同步。
摘要由CSDN通过智能技术生成

电商系统中,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信息

@PutMappingpublic void updateQuantity(@ApiIgnore@Valid @RequestBody List 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 skuList =goods.getSkuList();

Map skuMap = new HashMap<>(skuList.size());for(GoodsSkuVO sku : skuList){

skuMap.put(sku.getSkuId(), sku);

}

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

//要更新的库存列表

List 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()

}

实际库存和可用库存 库存

//实际库存

GoodsQuantityVO actualQuantityVo = newGoodsQuantityVO();//用传递的数量-现有的,就是变化的,如传递的是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(ListgoodsQuantityList) {

List skuIdList = newArrayList();

List goodsIdList = newArrayList();

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 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);

}

}returnresult;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值