文章

数据库实体设计商品(1.1)之商品信息

数据库实体设计商品(1.1)之商品信息

艿艿目前正在做一个开源的电商项目,胖友可以 star 下。https://gitee.com/zhijiantianya/onemall

1. 概述

本文主要分享商品模块的商品信息的数据库实体设计

基于如下信息,逆向猜测数据库实体:

【护脸旁白】笔者非电商行业出身 && 非有赞工程师,所以有错误或不合理的地方,烦请斧正和探讨。有赞是个各方面都很 NICE 的公司,推荐

2. 背景了解

在看具体的数据库实体设计之前,我们先一起了解下电商的名词定义有赞微商城界面

2.1 名词定义

参考 《产品 SKU 是什么意思?与之相关的还有哪些?》 整理。

SKU:Stock Keeping Unit

中文翻译为库存单位。SKU 从库存视角,以库存进出为单位,可以是件、瓶、箱等等。

例如,iPhone 手机,按照规格( 颜色 + 内存 )可以组合出如下多个 SKU :

SKU颜色内存
A白色16G
B白色64G
C黑色16G
D黑色64G

可以看出,颜色(白色、黑色)与内存(16G、64G)组合排列出四种 iPhone SKU。

SPU:Standard Product Unit

中文翻译为标准产品单位。SPU 从产品视角,是产品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。通俗点讲,属性值、特性相同的商品就可以被称为一个 SPU 。例如 iPhone 8 就是一个 SPU ,iPhone 8 Plus 也是一个 SPU ,这个与商家无关,与颜色、款式、套餐等规格无关。

商品

商家出售某个 SPU ,那么这就是一个商品。商品在 SPU 之上,增加了销售价格、促销活动、运费等等信息。另外,一个商品可以包含多个 SKU

总结

SKU、SPU、商品关系图


现实的场景往往比定义复杂的多,在本文中,SKU 代表销售的单元。主要考虑如下两方面:

  • 实际我们看到的商品详情页,购买的是一个销售组合单元 。例如,很多商家会打包 【iPhone X :银色-64G-套餐三】,其中套餐三为赠送贴膜 + 保护壳等等,当然价格上会更贵。这明显就违背了我们上述提到 SKU 库存的概念,已经变成了多个 SKU 的销售组合单元。 商品销售组合单元示例
  • 一个商家会在不同平台销售商品,例如三只松鼠,其在天猫、京东等等平台都有官方旗舰店,同时也供货给其他渠道商,那么实际关系会变成如下图所示: 多平台销售商品关系图 通过这样的方式,三只松鼠在不同的平台,定义不同的价格,设置不同的促销信息等等个性化的运营。

那么注意了!!!下文开始,SKU 代表销售的单元下文开始,SKU 代表销售的单元下文开始,SKU 代表销售的单元

2.2 界面

  1. 商城端-购买页 商城端购买页界面
  2. 运营后台-商品发布页 运营后台商品发布页界面

3. 数据库实体

整体实体类关系如下图:

整体实体类关系图

全部实体在 Github 商品实体目录 下可见。

3.1 Item

Item 字段较多,我们进行简单的切块。

3.1.1 基础字段

1
/**  * 编号  */ private Integer id; /**  * 别名  *  * 系统生成,作为唯一标识。例如,2fpa62tbmsl9h  */ private String alias; /**  * 店铺编号  */ private Integer shopId; /**  * 创建时间  */ private Date createTime; /**  * 更新时间  */ private Date updateTime; /**  * 状态  *  * 1-正常  * 2-删除  */ private Integer status;

  • id ,Item 编号,自增。数据类型是使用 Integer 还是 Long ,胖友可以根据自己的系统需要做调整。
  • aliashttps://h5.youzan.com/v2/goods/3f1o7jxm0gshh ,别名,系统自动生成,作为唯一标识。例如, “2fpa62tbmsl9h” 。目前有赞商城商品详情地址使用别名而不使用编号,防止无脑抓取。例如, 。
  • shopId ,店铺编号。有赞是基于 Sass 模式,支持多商户( 店铺 )。

3.1.2 基本信息

1
/**  * 商品标题  *  * 不能超过100字,受违禁词控制  */ private String title; /**  * 副标题,分享链接时显示  */ private String summary; /**  * 商品描述。  *  * 字数要大于5个字符,小于25000个字符 ,受违禁词控制  */  @Deprecated private String desc; /**  * 商品分类的叶子类目编号  *  * 有赞——店铺主营类目和商品类目对应表:https://bbs.youzan.com/forum.php?mod=viewthread&tid=25252  */ private Integer cid; /**  * 商品主图地址  *  * 数组,以逗号分隔  *  * 建议尺寸:800*800像素,你可以拖拽图片调整顺序,最多上传15张  */ private String picURLs; /**  * 商品类型  *  * 0:普通商品(物流发货)  * 3:UMP降价拍  * 5:外卖商品  * 10:分销商品  * 20:会员卡商品  * 21:礼品卡商品  * 22:团购券  * 25:批发商品  * 30:收银台商品  * 31:知识付费商品  * 35:酒店商品(无需物流)  * 40:美业商品  * 60:虚拟商品(无需物流)  * 61:电子卡券(无需物流)  */ private Integer itemType; /**  * 商品类型  *  * 0:自营商品  * 10:分销商品  */ private Integer goodsType;

3.1.3 价格库存

1
/**  * 价格,单位分  */ private Integer price; /**  * 商品重量,没有SKU时用  */ private Double itemWeight; /**  * 商品货号(商家为商品设置的外部编号)  */ private String itemNo; /**  * 总库存  *  * 基于 sku 的库存数量累加  */ private Integer quantity; /**  * 总销量  */ private Integer soldNum; /**  * 是否隐藏商品库存。在商品展示时不显示商品的库存。  *  * 0 - 显示库存(默认)  * 1 - 不显示库存  */ private Integer hideStock; /**  * 商品划线价格,可以自定义。例如 促销价:888  *  * 商品没有优惠的情况下,划线价在商品详情会以划线形式显示。  */ private Double originPrice; /**  * 是否参加会员折扣。  *  * 1 - 参加会员折扣(默认)  * 0 - 不参加会员折扣  */ private Integer joinLevelDiscount;

  • Item SKU 相关,有赞分成两种情况:
    • 第一种,无 SKU 的情况, price 、 itemWeight 、 quantity 、 soldNum 、 itemNo 对应这个商品的价格库存等信息。
    • 第二种,有 SKU 的情况, price 、 itemWeight 、 quantity 、 soldNum 、 itemNo 对应这个商品 SKU 的整体情况。其中, price 对应 SKU 最低价格。
    • ps:关于第一种的情况,也可以通过虚拟没有规格的 SKU ,这样和第二种的情况就可以等价了。
  • price分注意元 ,价格,单位为 ,避免 Double 在根据营销优惠信息计算价格时,精度丢失。 ,如果胖友一定要使用单位为 ,在 Java 里请使用 BigDecimal 。
  • joinLevelDiscount ,是否参加会员折扣。有赞支持会员卡功能,可以对商品进行优惠打折。 会员折扣界面
  • itemNo通过该字段,打通不同系统的信息 ,商品货号。商家为商品设置的外部编号,例如,ERP 系统。 。

3.1.4 运费信息

1
/**  * 运费类型  *  * 1-统一运费  * 2-运费模板  */ private Integer postType; /**  * 运费,单位分  */ private Integer postFee; /**  * 运费模版id  */ private Integer deliveryTemplateId;

3.1.5 其他信息

1
/**  * 是否上架商品。  *  * true 为已上架  * false 为已下架  */ private Boolean isListing; /**  * 排序字段  */ private Integer order; /**  * 开始出售时间。  *  * 没设置则为空  */ private Date autoListingTime; /**  * 商品是否锁定。  *  * true 为已锁定  * false 为未锁定  */ private Boolean isLock; /**  * 留言表单数组配置  *  * JSON 字符串 [{  *     name: // 表单名,String  *     required: // 是否必填,Integer,1-必填;0-选填  *     type: // 表单类型,String,枚举:文本格式/数字格式/邮件/日期/时间/身份证号/图片  *     multiple: // 是否多行,Integer,1-多行,0-单行  *     datetime:// 是否包含日期,用于 `type=时间`  * }]  */ private String messages;

  • isListing ,是否上架商品。
    • true ,已上架,用户可见,直到售罄( quantity = 0 )。售罄时,该状态不变,通过库存判断。
    • false ,已下架,在仓库,用户不可见。 - 商品上架状态界面
  • order ,排序字段。手动填写数字设置,序号越大越靠前。 商品排序设置界面
  • messages ,留言表单数组配置。 留言表单配置界面1 留言表单配置界面2

3.1.6 ItemEtd

ItemEtd,预售扩展信息

1
/**  * Item 编号  *  * {@link Item#id}  */ private Integer id; /**  * 发货类型  *  * 0 - xxx 时间开始发货  * 1 - 付款 n 天后发货。  */ private Integer etdType; /**  * 预计发货开始时间, 字符串格式的时间,格式如:2018-01-01  */ private Date etdStartDate; /**  * 付款成功 后发货天数, 默认0  */ private Integer etdDays;

来自老徐的提示:

  1. 字段以 Date 结尾,用于仅有日期格式的时间。
  2. 字段以 Time 结尾,用于带有时间格式的时间。

3.1.7 ItemFenxiao

ItemFenxiao,分销扩展信息

1
/**  * Item 编号  *  * {@link Item#id}  */ private Integer id; /**  * 供货店铺Id  */ private Integer supplierShopId; /**  * 供货商品Id  */ private Integer supplierItemId;

  • 通过 Item 的 goodsType = 10 判断为分销商品。
  • id ,Item 编号,1:1 指向对应的 Item 。

3.1.8 ItemPurchaseRight

ItemPurchaseRight,购买权限拓展信息

1
/**  * Item 编号  *  * {@link Item#id}  */ private Integer id; /**  * 允许购买的粉丝标签用,号分隔  *  * 数组,以逗号分隔  */ private String umpTags; /**  * 允许购买的粉丝等级,用逗号分隔  */ private String umpLevels; /**  * 每人限购多少件。0代表无限购,默认为0  */ private Integer buyQuota;

  • 通过 Item 的 purchaseRightStatus 字段,开启和关闭商品购买权限。
  • id ,Item 编号,1:1 指向对应的 Item 。 - 购买权限设置界面

3.2 ItemSku

ItemSku,商品 SKU 。

ItemSku实体结构图

1
/**  * 唯一编码,店铺Id 和 商品skuId 组合  *  * 分销场景下,skuId 多个店铺相同,uniqueCode 不同  */ private String uniqueCode; /**  * sku 编号  *  * 非唯一  */ private Integer skuId; /**  * 商品编号  */ private Integer itemId; /**  * 店铺编号  */ private Integer shopId; /**  * 状态  *  * 1-正常  * 2-删除  */ private Integer status; /**  * 图片地址  */ private String imageURL; /**  * 商品规格  *  * 格式:kid[0]-vid[0],kid[1]-vid[1]...kid[n]-vid[n]  * 例如:20000-3275069,1753146-3485013  */ private String properties; /**  * 商品货号(商家为商品设置的外部编号)  */ private String itemNo; /**  * 价格,单位分  */ private Integer price; /**  * 库存数量  */ private Integer quantity; /**  * 商品在付款减库存的状态下,该Sku上未付款的订单数量  */ private Integer withHoldQuantity; /**  * 销量  */ private Integer soldNum; /**  * 创建时间  */ private Date createTime; /**  * 更新时间  */ private Date updateTime;

  • uniqueCode唯一注意相同唯一引入 ,SKU 编码,格式为 shopId{skuId} 。 ,在分销场景下,引入商品的 skuId ,而 shopId 不同。通过该字段,保证 。
  • skuId ,SKU 编号,自增,非唯一,参见分销场景。
  • itemId ,Item 编号,N:1 指向对应的 Item 。
  • status正常 ,SKU 状态。编辑商品时,当规格属性发生变化时,优先重用( 保留 ) 状态的 SKU ,标记删除移除的 SKU ,例如:
    • 颜色:红;尺寸:X、L;
    • SKU 如下:
      • 【1】红-X
      • 【2】红-L
    • ————— 分隔 —————
    • 新增颜色,蓝;
    • SKU 如下:
      • 【1】红-X
      • 【2】红-L
      • 【3】蓝-X
      • 【4】蓝-L
    • ————— 分隔 ——————
    • 删除颜色,红;
    • SKU 如下:
      • 【3】蓝-X
      • 【4】蓝-L
  • properties ,商品规格,字符串拼接格式。
    • 绝大多数情况下,数据库里的该字段,不存在检索的需求,更多的时候,是查询整体记录,在内存中解析使用。
    • 少部分情况,灵活的检索,使用 Elasticsearch 进行解决。
  • quantity ,库存数量。在分销场景下,因为 skuId 相同,所以根据 skuId 可以批量修改,解决分销库存的同步问题。
  • withHoldQuantity ,商品在付款减库存的状态下( 例如秒杀场景 ),该 SKU 上未付款的订单数量。
  • itemNo通过该字段,打通不同系统的信息 ,商品货号。商家为商品设置的外部编号,例如,ERP 系统。 。

3.3 ItemSkuProperty

ItemSkuProperty,Item SKU 规格属性。

1
plain public class ItemSkuProperty {      /**      * 属性编号      */     private Integer id;     /**      * 属性文本      */     private String name;     /**      * 添加时间      */     private Date addTime;  }

  • id ,属性编号。
  • name注意 ,属性文本。 ,当规格名( PropertyKey )和规格值( PropertyValue )使用相同文本,对应的编号相同。例如, 规格属性编号示例
  • PropertyKey 与 PropertyValue 通过 「3.3.2 ItemSkuPropertyValueReference」 关联。

有赞的规格属性,这样的设定感觉有丢丢怪怪的,笔者后面调研了淘宝和微店的 Item SKU 规格属性的设计。


微店

微店规格属性设计

分成 ItemSkuPropertyKey 和 ItemSkuPropertyValue 两个表,并且 ItemSkuPropertyValue 相同字符串时,不同编号。


淘宝

不同类目固定可选的商品规格名,并且部分商品规格不能自定义规格值

  • 男装»背心/马甲 淘宝男装规格属性
  • 箱包皮具/热销女包/男包»卡包 淘宝箱包规格属性

不同于有赞、微店,淘宝、京东是支持全平台进行检索,而有赞、微店是没有这方面的需求。

淘宝商品属性搜索界面

那么规格和类目做关联一定合适么?笔者觉得不一定。类目和规格的关联整理是非常大的工作量,一旦整理缺失,反倒给上架带来不好的体验。而且,有赞、微店存在较多微商,非标的商品较多,需要更多灵活的空间。

另外,淘宝商品的属性拆分的很细,猜测分成如下:

同时,属性的类型除了包括选项完,也可以是文本、数值、百分比等等。

淘宝商品属性类型


推荐阅读 《B2C电子商务系统研发——商品SKU分析和设计(一)》 ,里面对SKU属性的管理做了很有借鉴性的思考。

3.3.1 ItemSkuPropertyKeyReference

ItemSkuPropertyKeyReference ,Item SKU 规格名引用。用于和店铺关联,不同店铺有不同的规格名引用数据。

1
/**  * 编号  */ private Integer id; /**  * 店铺编号  */ private Integer shopId; /**  * 属性键编号  *  * {@link ItemSkuProperty#id}  */ private Integer keyId; /**  * 添加时间  */ private Date addTime;

3.3.2 ItemSkuPropertyValueReference

ItemSkuPropertyValueReference ,Item SKU 规格值引用。用于和店铺关联,不同店铺有不同的规格值引用数据。

1
/**  * 编号  */ private Integer id; /**  * 店铺编号  */ private Integer shopId; /**  * 关联编号  *  * {@link ItemSkuPropertyKeyReference#id}  */ private Integer referenceId; /**  * 属性键编号  *  * {@link ItemSkuProperty#id}  */ private Integer keyId; /**  * 属性值编号  *  * {@link ItemSkuProperty#id}  */ private Integer valueId; /**  * 添加时间  */ private Date addTime;

4. API

基于 有赞云提供的商品API ,整理如下 API 类。

4.1 ItemAPI

ItemAPI ,商品 API 。

ItemAPI类结构图

4.2 ItemSkuAPI

ItemSkuAPI ,商品 SKU API 。

ItemSkuAPI类结构图

666. 彩蛋

第一次尝试写这种类型的文章,如果内容有错误的地方,烦请斧正。如果有写的不详细或者不明白的地方,欢迎一起探讨。

推荐与参考文章:

本文由作者按照 CC BY 4.0 进行授权