一、多规格商品的核心需求
1. 商品多样性
生鲜商品(如水果、肉类)常存在重量、包装、品质等级等差异(如“300g±10%的苹果”“进口A级牛排”),需支持用户按规格选择。
2. 价格动态计算
不同规格对应不同价格(如按斤计价、按份计价),需实时计算总价。
3. 库存精准管理
需区分各规格库存,避免超卖(如“小份装”与“大份装”库存独立)。
4. 用户友好交互
提供清晰的规格选择界面(如单选、多选、组合购),减少用户决策成本。
二、系统架构设计
1. 数据库设计
- 商品表(Goods)
存储商品基础信息(ID、名称、分类、描述等)。
- 规格表(Specification)
定义规格类型(如重量、包装、品质)及其可选值(如“500g”“1kg”“礼盒装”)。
- 商品规格关联表(Goods_Spec)
关联商品与规格,记录各规格的SKU、价格、库存、条形码等。
- 库存表(Inventory)
按SKU管理实时库存,支持分布式锁防止超卖。
示例数据模型:
```sql
-- 商品表
CREATE TABLE Goods (
id INT PRIMARY KEY,
name VARCHAR(100),
category_id INT
);
-- 规格表
CREATE TABLE Specification (
id INT PRIMARY KEY,
name VARCHAR(50), -- 如"重量"、"包装"
type VARCHAR(20) -- 如"weight"、"package"
);
-- 规格值表
CREATE TABLE Spec_Value (
id INT PRIMARY KEY,
spec_id INT,
value VARCHAR(50), -- 如"500g"、"1kg"
FOREIGN KEY (spec_id) REFERENCES Specification(id)
);
-- 商品规格关联表
CREATE TABLE Goods_Spec (
id INT PRIMARY KEY,
goods_id INT,
spec_value_ids VARCHAR(255), -- 存储多个规格值ID(如"1,2"对应500g+普通装)
sku VARCHAR(50),
price DECIMAL(10,2),
stock INT,
FOREIGN KEY (goods_id) REFERENCES Goods(id)
);
```
2. 前端交互设计
- 规格选择组件
使用级联选择器(Cascader)或单选/多选按钮,动态展示可选规格组合。
- 价格实时更新
用户选择规格后,通过AJAX请求后端接口获取对应价格,避免页面刷新。
- 库存提示
当用户选择规格时,显示剩余库存(如“仅剩3件”),并禁用售罄选项。
示例交互流程:
1. 用户进入商品详情页,系统加载所有规格选项。
2. 用户选择“重量:500g” → 前端发送请求至`/api/goods/{id}/price?spec=500g`。
3. 后端查询数据库,返回价格`9.9元`,前端更新显示。
3. 后端逻辑实现
- 规格组合校验
确保用户选择的规格组合有效(如“500g+礼盒装”需存在对应SKU)。
- 价格计算
根据规格组合从`Goods_Spec`表中查询价格,支持促销活动(如满减、折扣)。
- 库存扣减
下单时通过分布式锁(如Redis)扣减对应SKU库存,避免并发超卖。
关键代码片段(Java示例):
```java
// 查询规格组合价格
public BigDecimal getPriceBySpec(Long goodsId, List specValueIds) {
String specKey = String.join(",", specValueIds.stream().map(String::valueOf).collect(Collectors.toList()));
GoodsSpec spec = goodsSpecRepository.findByGoodsIdAndSpecValues(goodsId, specKey);
if (spec == null) {
throw new RuntimeException("规格组合不存在");
}
return spec.getPrice();
}
// 下单时扣减库存
@Transactional
public void deductStock(Long skuId, int quantity) {
Inventory inventory = inventoryRepository.findBySkuId(skuId);
if (inventory.getStock() < quantity) {
throw new RuntimeException("库存不足");
}
inventory.setStock(inventory.getStock() - quantity);
inventoryRepository.save(inventory);
}
```
三、业务场景优化
1. 组合销售
支持“水果礼盒”(多个规格商品组合)的独立定价与库存管理。
2. 动态规格
生鲜商品重量可能浮动(如“称重商品”),系统需支持按实际重量计价(如用户下单时输入重量,系统按单价计算)。
3. 缺货替代
当某规格缺货时,推荐相似规格(如“500g缺货,推荐1kg装享8折”)。
四、技术挑战与解决方案
1. 规格组合爆炸
- 问题:商品规格过多会导致SKU数量指数级增长。
- 方案:使用规格模板(如“水果类”统一重量规格),或动态生成SKU(仅存储有效组合)。
2. 高性能查询
- 问题:规格查询需快速响应。
- 方案:对`Goods_Spec`表的`spec_value_ids`字段建立索引,或使用Elasticsearch加速检索。
3. 分布式事务
- 问题:库存扣减需保证原子性。
- 方案:采用Seata等分布式事务框架,或通过消息队列实现最终一致性。
五、总结
叮咚买菜的多规格商品销售系统需通过数据库设计优化、前后端交互细化和业务逻辑封装实现。核心在于:
- 数据模型:清晰定义商品、规格、SKU的关系。
- 用户体验:提供直观的规格选择界面与实时反馈。
- 系统稳定性:通过分布式锁、事务管理确保库存准确性。
通过以上设计,系统可支持生鲜电商复杂的多规格销售场景,同时兼顾扩展性与性能。