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_id | BIGINT | 主键 | 1001 |
| brand_id | BIGINT | 品牌ID(外键) | 205(苹果品牌ID) |
| category_id | BIGINT | 分类ID(外键) | 3(手机分类ID) |
| spu_name | VARCHAR(255) | SPU名称 | iPhone 15 |
| base_price | DECIMAL(10,2) | 基准价(用于价格区间展示) | 5999.00 |
| status | TINYINT | 上下架状态(0-下架,1-上架) | 1 |
2.2.2 SKU主表(sku)
| 字段名 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| sku_id | BIGINT | 主键 | 30001 |
| spu_id | BIGINT | 所属SPU ID(外键) | 1001 |
| sku_code | VARCHAR(50) | SKU唯一编码(业务标识) | IP15-BLK-256 |
| price | DECIMAL(10,2) | 实际销售价格 | 6999.00 |
| main_image | VARCHAR(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英寸
处理方案:
- 创建新SPU(ID=1002)
- 逐步迁移关联SKU
- 旧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设计,既能满足电商系统复杂的业务需求,又能保证系统的高性能运行。关键在于理解业务本质,做好数据模型的抽象与平衡。