商品SKU功能設計與優化

SpringBoot實戰電商項目mall(30k+star)地址:github.com/macrozheng/…前端

摘要

原來的商品SKU設計存在着兩個問題,一個是SKU表設計上面比較固化,沒法擴展。另外一個是當修改了商品信息以後,商品SKU的ID會發生變化,因爲購物車表和訂單商品表都關聯了商品SKU的ID,這樣就會致使匹配不上。最近對這兩個問題作了點優化,下面來聊聊優化的思路。java

商品的SPU和SKU

首先咱們來了解下商品SPU和SKU的概念,可能不少沒有接觸過電商的朋友都不瞭解。git

  • SPU(Standard Product Unit ):指的是標準商品單位,商品信息聚合的最小單位,是一組可複用、易檢索的標準化信息的集合,該集合描述了一個商品的特性;
  • SKU(Stock Keeping Unit):庫存量單位,是物理上不可分割的最小存貨單元。

舉個例子:好比說如今有個手機商品叫小米8,小米8有不一樣的屬性,好比有它有黑色和藍色的,有32G和64G版本的。此時小米8就是一個SPU,而小米8黑色64G就是一個SKU。github

商品的SKU設計

之前的設計

商品的SKU信息是存儲在pms_sku_stock表中的,使用sp一、sp二、sp3這三個屬性來存儲商品的銷售屬性,這樣作很不靈活,也難以擴展。數據庫

這種作法也帶來了後續的問題,好比咱們的購物車和訂單都會須要存儲銷售屬性,這樣的話都會須要添加sp一、sp二、sp3的屬性。json

改進後的設計

因爲商品的銷售屬性是動態的,無法肯定到底有多少個,此時咱們能夠改用JSON格式來存儲,在pms_sku_stock表中添加了sp_data字段。數組

sp_data存儲的就是一個JSON數組,好比顏色爲黑色,容量爲32G的手機存儲信息以下。app

[
    {
        "key": "顏色",
        "value": "黑色"
    },
    {
        "key": "容量",
        "value": "32G"
    }
]
複製代碼

這樣修改之後,在原來的購物車表oms_cart_item和訂單商品表oms_order_item中就均可以用JSON格式來存儲銷售屬性了,使用的是product_attr字段。ide

商品關聯SKU的修改

之前的作法

商品的SKU信息做爲商品的關聯信息,在修改商品信息時會同時進行修改。之前的作法是直接刪除該商品的全部SKU信息,再從新添加。這樣就會致使商品SKU中的ID被修改,因爲在購物車和訂單商品中關聯了商品SKU的ID,就會致使原來的ID失效的問題。下面是原來修改商品中SKU信息的代碼。學習

/** * 商品管理Service實現類 * Created by macro on 2018/4/26. */
@Service
public class PmsProductServiceImpl implements PmsProductService {
    
        @Override
        public int update(Long id, PmsProductParam productParam) {
            //省略若干代碼...
            //刪除該商品關聯的SKU
            PmsSkuStockExample skuStockExample = new PmsSkuStockExample();
            skuStockExample.createCriteria().andProductIdEqualTo(id);
            skuStockMapper.deleteByExample(skuStockExample);
            handleSkuStockCode(productParam.getSkuStockList(),id);
            //插入傳入的全部SKU
            relateAndInsertList(skuStockDao, productParam.getSkuStockList(), id);
        }
}
複製代碼

改進後的作法

首先咱們須要和前端約定下,新增的商品SKU信息不傳ID,要修改的商品SKU信息傳ID,刪除的直接不傳SKU信息。而後咱們能夠根據傳入的SKU信息來肯定須要新增、修改、刪除的SKU信息,這樣就能夠作到在更新商品SKU信息時,不改變原來商品SKU的ID了,具體流程以下。

具體代碼實現以下:

/** * 商品管理Service實現類 * Created by macro on 2018/4/26. */
@Service
public class PmsProductServiceImpl implements PmsProductService {
    private void handleUpdateSkuStockList(Long id, PmsProductParam productParam) {
        //當前的sku信息
        List<PmsSkuStock> currSkuList = productParam.getSkuStockList();
        //當前沒有sku直接刪除
        if(CollUtil.isEmpty(currSkuList)){
            PmsSkuStockExample skuStockExample = new PmsSkuStockExample();
            skuStockExample.createCriteria().andProductIdEqualTo(id);
            skuStockMapper.deleteByExample(skuStockExample);
            return;
        }
        //獲取初始sku信息
        PmsSkuStockExample skuStockExample = new PmsSkuStockExample();
        skuStockExample.createCriteria().andProductIdEqualTo(id);
        List<PmsSkuStock> oriStuList = skuStockMapper.selectByExample(skuStockExample);
        //獲取新增sku信息
        List<PmsSkuStock> insertSkuList = currSkuList.stream().filter(item->item.getId()==null).collect(Collectors.toList());
        //獲取須要更新的sku信息
        List<PmsSkuStock> updateSkuList = currSkuList.stream().filter(item->item.getId()!=null).collect(Collectors.toList());
        List<Long> updateSkuIds = updateSkuList.stream().map(PmsSkuStock::getId).collect(Collectors.toList());
        //獲取須要刪除的sku信息
        List<PmsSkuStock> removeSkuList = oriStuList.stream().filter(item-> !updateSkuIds.contains(item.getId())).collect(Collectors.toList());
        handleSkuStockCode(insertSkuList,id);
        handleSkuStockCode(updateSkuList,id);
        //新增sku
        if(CollUtil.isNotEmpty(insertSkuList)){
            relateAndInsertList(skuStockDao, insertSkuList, id);
        }
        //刪除sku
        if(CollUtil.isNotEmpty(removeSkuList)){
            List<Long> removeSkuIds = removeSkuList.stream().map(PmsSkuStock::getId).collect(Collectors.toList());
            PmsSkuStockExample removeExample = new PmsSkuStockExample();
            removeExample.createCriteria().andIdIn(removeSkuIds);
            skuStockMapper.deleteByExample(removeExample);
        }
        //修改sku
        if(CollUtil.isNotEmpty(updateSkuList)){
            for (PmsSkuStock pmsSkuStock : updateSkuList) {
                skuStockMapper.updateByPrimaryKeySelective(pmsSkuStock);
            }
        }

    }
}
複製代碼

總結

若是咱們要在數據庫中存儲一些格式不固定的屬性時,能夠採用JSON的形式進行存儲。對於關聯屬性的修改,能夠經過一些邏輯操做來實現不改變原有ID的修改。

項目源碼地址

github.com/macrozheng/…

公衆號

mall項目全套學習教程連載中,關注公衆號第一時間獲取。

公衆號圖片
相關文章
相關標籤/搜索