SPU与SKU设计详解:从概念到数据库落地

3,987 阅读4分钟

SPU与SKU设计详解:从概念到数据库落地

一、SPU与SKU的本质区别

1.1 概念对比

SPU(标准产品单元)SKU(库存单元)
定位商品聚合根(如iPhone 15)具体销售单元(如iPhone15 黑色 256GB)
数据特征描述共性特征(品牌、分类、基础参数)记录个性特征(颜色、规格、价格)
库存管理不直接管理库存库存管理的最小单位
示例小米电视EA75 2023款小米电视EA75 75英寸 黑色 官方标配

1.2 核心差异点

graph TD
    SPU -->|1:N| SKU
    SPU -->|定义| 公共属性
    SKU -->|继承+扩展| 销售属性
    SKU -->|关联| 库存信息

二、数据库表结构设计

2.1 核心表ER图

erDiagram
    BRAND ||--o{ SPU : "1:N"
    CATEGORY ||--o{ SPU : "1:N"
    SPU ||--o{ SPU_ATTR_VALUE : "1:N"
    SPU ||--o{ SKU : "1:N"
    SKU ||--|| SKU_STOCK : "1:1"
    SKU ||--o{ SPU_SKU_ATTR_VALUE : "1:N"
    ATTR ||--o{ SPU_ATTR_VALUE : "1:N"
    ATTR ||--o{ SPU_SKU_ATTR_VALUE : "1:N"

2.2 关键表结构详解

2.2.1 SPU主表(spu)
字段名类型说明示例值
spu_idBIGINT主键1001
brand_idBIGINT品牌ID(外键)205(苹果品牌ID)
category_idBIGINT分类ID(外键)3(手机分类ID)
spu_nameVARCHAR(255)SPU名称iPhone 15
base_priceDECIMAL(10,2)基准价(用于价格区间展示)5999.00
statusTINYINT上下架状态(0-下架,1-上架)1
2.2.2 SKU主表(sku)
字段名类型说明示例值
sku_idBIGINT主键30001
spu_idBIGINT所属SPU ID(外键)1001
sku_codeVARCHAR(50)SKU唯一编码(业务标识)IP15-BLK-256
priceDECIMAL(10,2)实际销售价格6999.00
main_imageVARCHAR(255)主图地址/images/ip15-blk.jpg
2.2.3 属性相关表
-- 属性定义表(attr)
CREATE TABLE attr (
    attr_id BIGINT PRIMARY KEY COMMENT '属性ID',
    attr_name VARCHAR(50) NOT NULL COMMENT '属性名称',
    attr_type TINYINT NOT NULL COMMENT '1-SPU属性 2-SKU属性'
);

-- SPU属性值表(spu_attr_value)
CREATE TABLE spu_attr_value (
    spu_id BIGINT,
    attr_id BIGINT,
    attr_value VARCHAR(255),
    PRIMARY KEY (spu_id, attr_id)
);

-- SKU属性关联表(spu_sku_attr_value)
CREATE TABLE spu_sku_attr_value (
    sku_id BIGINT,
    attr_id BIGINT, 
    attr_value VARCHAR(255),
    PRIMARY KEY (sku_id, attr_id)
);
2.2.4 库存相关表
-- SKU库存表(sku_stock)
CREATE TABLE sku_stock (
    sku_id BIGINT PRIMARY KEY,
    total_stock INT NOT NULL COMMENT '总库存',
    available_stock INT NOT NULL COMMENT '可用库存',
    locked_stock INT NOT NULL DEFAULT 0 COMMENT '锁定库存'
);

-- 库存锁定表(sku_stock_lock)
CREATE TABLE sku_stock_lock (
    lock_id VARCHAR(32) PRIMARY KEY COMMENT '锁定ID(订单号+SKU)',
    sku_id BIGINT NOT NULL,
    quantity INT NOT NULL,
    lock_status TINYINT NOT NULL COMMENT '1-锁定中 2-已释放',
    expire_time DATETIME NOT NULL
);

三、数据关联示例:iPhone 15

3.1 SPU基础数据

-- SPU主表
INSERT INTO spu VALUES 
(1001, 205, 3, 'iPhone 15', 5999.00, 1);

-- SPU属性值
INSERT INTO spu_attr_value VALUES
(1001, 1, '智能手机'),    -- 产品类型
(1001, 2, 'Apple A16'),  -- 处理器
(1001, 3, '6.1英寸');    -- 屏幕尺寸

3.2 SKU实例数据

-- SKU 1(黑色 128GB)
INSERT INTO sku VALUES
(30001, 1001, 'IP15-BLK-128', 5999.00, '/images/ip15-blk.jpg');

INSERT INTO spu_sku_attr_value VALUES
(30001, 4, '黑色'),      -- 颜色属性
(30001, 5, '128GB');     -- 存储容量

-- SKU 2(蓝色 256GB)  
INSERT INTO sku VALUES
(30002, 1001, 'IP15-BLU-256', 6999.00, '/images/ip15-blu.jpg');

INSERT INTO spu_sku_attr_value VALUES
(30002, 4, '蓝色'),
(30002, 5, '256GB');

3.3 库存数据

INSERT INTO sku_stock VALUES
(30001, 1000, 800, 200),
(30002, 500, 450, 50);

四、设计要点解析

4.1 属性管理核心逻辑

sequenceDiagram
    participant App
    participant SPU
    participant SKU
    
    App->>SPU: 创建SPU(定义基础属性)
    SPU->>attr: 选择SPU属性(处理器、屏幕等)
    App->>SKU: 基于SPU生成SKU
    SKU->>attr: 选择SKU属性(颜色、存储等)
    SKU->>spu_sku_attr_value: 保存具体属性值

4.2 库存扣减流程

public boolean deductStock(String orderId, Long skuId, int quantity) {
    // 1. 检查可用库存
    SkuStock stock = skuStockDao.get(skuId);
    if (stock.getAvailableStock() < quantity) {
        return false;
    }
    
    // 2. 创建锁定记录
    String lockId = orderId + "_" + skuId;
    skuStockLockDao.insert(
        new SkuStockLock(lockId, skuId, quantity)
    );
    
    // 3. 更新库存
    skuStockDao.updateAvailableStock(
        skuId, 
        stock.getAvailableStock() - quantity
    );
    
    return true;
}

五、常见问题解决方案

5.1 属性变更连锁反应

场景:SPU的屏幕尺寸从6.1改为6.2英寸
处理方案

  1. 创建新SPU(ID=1002)
  2. 逐步迁移关联SKU
  3. 旧SPU标记为历史版本

5.2 SKU爆炸式增长

优化策略

-- 使用JSON存储部分属性
ALTER TABLE sku ADD COLUMN spec_json JSON COMMENT '规格属性';

-- 示例存储
{
  "color": "黑色",
  "storage": "128GB",
  "version": "国行版"
}

5.3 库存超卖问题

解决方案

-- 使用CAS(Compare And Set)操作
UPDATE sku_stock 
SET available_stock = available_stock - #{quantity}
WHERE sku_id = #{skuId} 
AND available_stock >= #{quantity}

六、设计总结

6.1 核心优势

  • 灵活性:通过属性表实现动态规格管理
  • 扩展性:轻松支持多级分类、多品牌场景
  • 性能:库存数据与SKU强绑定,保证扣减效率

6.2 适用场景

场景适用表说明
商品详情展示spu + spu_detail展示商品图文详情
商品列表筛选spu_attr_value + category根据属性快速过滤
购物车操作sku + sku_stock实时库存校验
订单支付sku_stock_lock保证库存一致性

通过合理的SPU/SKU设计,既能满足电商系统复杂的业务需求,又能保证系统的高性能运行。关键在于理解业务本质,做好数据模型的抽象与平衡。