电商项目数据库设计 | 参考京东商城详细讲解商品数据库设计

围绕商品设计表

之前也写过类似的数据库设计方案,这一篇是为大家详细讲解参考京东商城围绕商品怎么来设计数据库,需要关注的细节很多,对字段进行详解,结合功能实现分析每一个字段设计的意义

大家看完这篇文章后可以看看前面四篇文章电商项目数据库设计方案,跟这一篇有点不同,之前是大多是参照苏宁易购来设计的

我们在设计数据库的时候,大多都是按照我们自己的实际需求来设计,提供这几篇仅为大家参考学习,能够举一反三参与到项目实战中,希望大家可以学到东西,同时,文章内容如果有错误的位置希望大家可以指正,共同学习。


接下来我们就言归正传,开始设计表

分类表 category

CREATE TABLE `tb_category` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类Id',
  `name` varchar(32) NOT NULL COMMENT '分类名称',
  `parent_id` bigint(20) NOT NULL COMMENT '父分类Id (顶级类目填0)',
  `is_parent` tinyint(1) NOT NULL COMMENT '是否为父节点 (0-否,1-是)',
  `sort` tinyint(2) NOT NULL COMMENT '排序指数,越小越靠前',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '数据创建时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '数据更新时间',
  PRIMARY KEY (`id`),
  KEY `key_parent_id` (`parent_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1424 DEFAULT CHARSET=utf8 COMMENT='商品类目表,类目和商品(spu)是一对多关系,类目与品牌是多对多关系'

截取京东首页,如下图:

左侧菜单栏,即显示的商品分类,分类表我们应该设置哪些字段,我们可以参照京东商城思考下:

首先作为关系型MySQL数据库,我们先定下通用字段,id、create_time、update_time这三个字段。

逻辑删除字段看大家需求,我这里是自己做demo,就没有设置逻辑删除字段了,is_delete boolean类型,之前也写过仿照苏宁易购设计过数据库,大家可以参考着看,仅供学习使用。

看上图,我依次在菜单里面框出三个,在分类表中我们如何对菜单进行表示,字段名如何设置,很简单,设置成level1、level2、level3三个字段分别表示就可以了,level1表示一级菜单,level2表示二级菜单,level3表示三级菜单。

但是想想,我们在实际业务中,如果我们开发一个商城以后有亿级用户,想添加其他的分类后,是不是要加level4、level5·····,这样设计就有点不灵活了。

所以我们可以这样设计,设计一个 parent_id 用来表示父类目id进行关联,顶级类目就是0,满足可扩展性,而且字段也不冗余,符合三范式设计,什么是数据库设计三范式,https://blog.csdn.net/weixin_42437102/article/details/106422548 不了解的同学可以看看这篇文章。

可以再设计一个 is_parentid 用来表示是否是父id,如果不是父id,肯定就是最后一次菜单,这里我不说是三级菜单,可能我们以后会进行扩展。

给一个 sort字段 进行权重分配,排序指数,指数越小越靠前,这里就设计好了分类表。


品牌表 brand

CREATE TABLE `tb_brand` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '品牌id',
  `name` varchar(64) NOT NULL COMMENT '品牌名称',
  `image` varchar(256) DEFAULT '' COMMENT '品牌图片地址',
  `letter` char(1) DEFAULT '' COMMENT '品牌的首字母',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=325403 DEFAULT CHARSET=utf8 COMMENT='品牌表,一个品牌下有多个商品(spu),一对多关系'

设计数据表,我们依旧先列出通用字段,id、create_time、update_time

截取京东页面:

从上图我们可以看出,品牌设计也不怎么复杂,我们先看最上面,所有品牌,首字母表示,所有我们设计一个letter字段,用来表示品牌的首字母,可以用来做搜索。

继续往下看,我们能看到什么?无非就是品牌的logo和名称了吧,那就设计name字段表示名称,image字段表示品牌的logo。还有没有什么?

逻辑删除也可以设置,这个放在关联关系表来说!


品牌分类表 category_brand

前面我们已经分析出了商品分类表和品牌表,它们之间有什么关系,我们这个阶段来屡屡。

首先我们还是回到京东首页,也就是我们在设计分类表的时候截取的京东那张图片,对边点击一个三级分类,我这里点的手机,是不是看到的是品牌表这里的图片,也就是说,一个分类下有多个品牌,如:(手机:有华为手机,苹果手机,小米手机···)

接下来看一张图:

华为品牌下也有很多分类,所以一个品牌下也有很多分类。

即分类表与品牌表是多对多的关系,多对多设计 中间表

CREATE TABLE `tb_category_brand` (
  `category_id` bigint(20) NOT NULL COMMENT '商品类目id',
  `brand_id` bigint(20) NOT NULL COMMENT '品牌id',
  PRIMARY KEY (`category_id`,`brand_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品分类和品牌的中间表,两者是多对多关系'

但是,你可能会发现,这张表中并没有设置外键约束,似乎与数据库的设计范式不符。为什么这么做?

  • 外键会严重影响数据库的读写效率
  • 数据删除时会比较麻烦

在电商行业,性能是非常重要的。我们宁可在代码中通过逻辑来维护表关系,也不设置外键。

如果使用逻辑删除是否可以解决这个问题,大家可以思考下。


商品规格参数

商品规格参数相关的表是我们围绕商品进行表设计所必不可少的,规格参数表应该如何设计 ?

通常情况下 一个商品有很多规格参数,比如一个手机,有品牌、产品名称、机身长度、机身重量、CPU、内存等等,把这些分别设计成字段,一张表也就几十个字段,但是想想,这样做会有什么不妥 ?

首先,我们设计数据库是设计一个全品类的电商平台,商品有很多种,我们打开京东看看,

手机的规格与包装:

空调的规格与包装:

还有很多很多,如果都设计到一张参数表,可想而知,是不合理的。

注意,我们发现 虽然商品不同、规格不同,但是同一个分类下的商品,比如都是手机,它们的规格参数名都是一样的,只是值不一样。所以,商品的规格参数应该 与 分类绑定每一个分类都有统一的规格参数模板不同商品的规格参数值是不同的

因此:

  • 规格参数的名称(key)与值(value)应该分开保存
  • 一个分类 对应 一套规格参数模板,参数模板只有规格参数的名称(key),没有值(value)
  • 一个分类 对应 多个商品,每个商品的规格参数值都不同,所以每个商品都有自己的一套规格参数值

所以我们引入参数组与参数表:

规格参数的值我们暂且先不管,新增商品时再填写规格参数值即可,我们先思考 规格参数模板(key)该怎么设计 ?

  • 规格数据首先要分组,每个组再有不同的规格参数
  • 一个分类规格模板中,有多个规格组
  • 每个规格组中,包含多个规格参数

从面向对象的思想来看,我们的 规格组 和 规格参数 分别是两类事物,并且组与组内参数成一对多关系,因此可以有两个类分别描述它们,那么从数据库设计来看,也就对应两张表:

  • 规格组表:tb_spec_group,一个商品分类下有多个规格组
  • 规格参数表:tb_spec_param,一个规格组下,有多个规格参数

如图:

接下来要思考的就是:

  • 描述规格组,需要哪些属性?

因为 商品分类表 与 规格组表 是一对多的关系,一个商品分类下有多个规格组,所以 规格组表 里要有 商品分类Id 进行关联,规格组表字段可以设置为:

id:规格组自增Id

category_id:商品分类Id

name:组名

create_time:创建时间

update_time:更新时间

  • 描述规格参数,需要哪些属性?

规格组表 与 规格参数表 也是一对多的关系,即一个组有多个参数,所以需要关联商品分类Id、规格组Id

想清楚上面的问题,就知道表该怎么设计了。

规格组表 spec_group

CREATE TABLE `tb_spec_group` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '规格组Id',
  `category_id` bigint(20) NOT NULL COMMENT '商品分类Id (一个分类下有多个规格组)',
  `name` varchar(32) NOT NULL COMMENT '规格组名称',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `key_category` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='规格参数的分组表,每个商品分类下有多个规格参数组';

还是老套路:固定的三个字段 id、create_time、update_time。

name:是组名。

category_id:因为一个商品分类下有多个规格参数组,一对多的关系,所以设计 category_id 关联,实现一对多。

规格参数表 spec_param

先看表设计:

CREATE TABLE `tb_spec_param` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '参数Id',
  `category_id` bigint(20) NOT NULL COMMENT '商品分类Id (参数所属的商品分类)',
  `group_id` bigint(20) NOT NULL COMMENT '规则组Id (参数所属的规格组)',
  `name` varchar(128) NOT NULL COMMENT '参数名',
  `numeric` tinyint(1) NOT NULL COMMENT '是否是数字类型参数 (true或false)',
  `unit` varchar(128) DEFAULT '' COMMENT '数字类型参数的单位 (非数字类型可以为空)',
  `generic` tinyint(1) NOT NULL COMMENT '是否是SKU通用规格 (true或false)',
  `searching` tinyint(1) NOT NULL COMMENT '是否用于搜索过滤 (true或false)',
  `segments` varchar(1024) DEFAULT '' COMMENT '区间 (数值类型参数的预设区间值,如果需要搜索,则添加分段间隔值,如CPU频率间隔:0.5-1.0)',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `key_group` (`group_id`),
  KEY `key_category` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='规格参数组下的参数名';

固定三个字段我们不需要过多的解释,这是我们的套路:id、create_time、update_time。

category_id、group_id:一个商品分类有多个规格参数组,一个规格参数组有多个规格参数。

name:很好解释,它是参数名。

接下来剩 numeric、unit、generic、searching、segments:

  • numeric:是否数值类型

上图中,我们需要用两个字段来描述:有的参数值是数字类型并且需要带单位,有的不是数字类型。

所以我们设计 numeric字段 作为一个标识(标识是否是数值),如果是数值类型就必须伴随着一个 unit字段 作为数字类型参数值的单位。

  • searching、segments 是用来做搜索用的,我们随便打开一个页面:

你会发现,过滤条件中的屏幕尺寸、运行内存、网路、机身内存、电池容量、CPU核数等,在规格参数中都能找到:

也就是说,规格参数中的数据,将来会有一部分作为搜索条件来使用。

我们可以在设计时,将这部分属性标记出来,将来做搜索的时候,作为过滤条件。

与搜索相关的有两个字段:

  • searching:标记是否用作过滤 

true - 用于过滤搜索,false - 不用于过滤

  • segments:某些数值类型的参数,如果在搜索时需要按区间划分的,要在这里提前确定好划分区间

比如电池容量,0-2000mAh,2000mAh-3000mAh,3000mAh-4000mAh

  • generic

一个全品类的电商网站 商品的种类繁多,每一件商品的属性又有差别。为了更准确描述商品及细分差别,抽象出两个概念:SPU和SKU,这里的generic属性,代表是否是通用属性,我们在商品数据结构时再聊,这里先了解一下。


商品表

了解SPU和SKU是什么 

SPU:Standard Product Unit (标准产品单位) ,一组具有共同属性的商品集

SKU:Stock Keeping Unit(库存量单位),在SPU商品集之下因具体特性不同而细分的每种商品

以图为例来看:

  • 本页的华为Mate10就是一个商品集。—> 华为Mate10 就是一个 SPU
  • 因为颜色、内存等规格的不同,在 “华为Mate10 商品集” 之下又细分出不同的 华为Mate10,比如:华为Mate10 亮黑色 128G版。—> 华为Mate10 亮黑色 128G版 就是一个 SKU

可以看出:

  • SPU是一个抽象的商品集概念,为了方便后台的管理
  • SKU才是具体要销售的商品,每一个SKU的价格、库存都不一样,用户购买的是SKU 而不是SPU。

弄清楚了SPU和SKU的概念,接下来我们就着手开始设计商品表SPU和SKU了。

先看看京东页面是怎么设计的,我们随便打开一个商品:

看着这个图片,我们自己来模拟设计下SPU表:

  • id:主键
  • c_id:分类ID
  • brand_id:品牌ID
  • name:商品名称
  • description:描述
  • spec:规格
  • after_service:售后服务
  • comment:评价

似乎并不复杂。

再看下SKU,大家觉得应该有什么字段?

  • id:主键
  • spu_id:关联的spu
  • price:价格
  • images:图片
  • stock:库存
  • 颜色?
  • 内存?
  • 硬盘?

SKU的特有规格也是变化的,不同商品,特有规格不一定相同,那么我们的表字段岂不是不确定 ?

SKU的特有规格应该怎么设计 ?

首先我们应该了解SKU的特有规格是什么,顾名思义,特有规格就是特有的,所有商品各自持有的,比如商品的内存,不同手机内存不一样,有4G、6G、8G、16G…,颜色有红色、绿色、黑色… 等等。

是不是SKU就是和商品分类有关系,在我这里,SKU特有规格 是和 商品规格参数有关系的,我们还是截取京东页面来看看,如下图:

  • 颜色 —> 对应五种
  • 内存 —> 对应三种

这都是在参数规格中可以看到的,点击哪一种,下面的参数就跟着变化。所以SKU的特有规格也是商品参数规格的一部分

也就是说,我们没必要单独对SKU的特有规格进行设计,它可以看做是规格参数中的一部分

这样,规格参数中的属性可以标记成两部分:

  • SPU 下所有SKU共享的规格参数(称为 通用规格)
  • SPU 下每个SKU不同的规格参数(称为 特有规格)

回想前面的伏笔,在设计的规格参数表时,有一个generic的字段 标记 “通用或特有规格”,就是为了这里使用。

这样,商品SKU表就只需要设计规格属性以外的其它字段了,商品SKU的规格参数由 之前设计好的 规格参数表 来保存,但 规格参数的值 依然是需要与商品相关联

接下来我们就来看看到底怎么设计:

SPU表   spu、spu_detail

CREATE TABLE `tb_spu` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'SPU Id',
  `name` varchar(256) NOT NULL DEFAULT '' COMMENT '商品名称',
  `sub_title` varchar(256) DEFAULT '' COMMENT '副标题 (一般是促销信息)',
  `cid1` bigint(20) NOT NULL COMMENT '1级分类Id',
  `cid2` bigint(20) NOT NULL COMMENT '2级分类Id',
  `cid3` bigint(20) NOT NULL COMMENT '3级分类Id',
  `brand_id` bigint(20) NOT NULL COMMENT '品牌Id (商品所属的品牌)',
  `saleable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否上架 (0-下架,1-上架)',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=187 DEFAULT CHARSET=utf8 COMMENT='spu表描述的是一个抽象性的商品,比如 iphone8'

tb_spu表与我们前面分析的基本类似,但是少了一些字段,比如商品描述等。

这里对SPU做了表的垂直拆分,把SPU的详情放到了另一张表  tb_spu_detail

CREATE TABLE `tb_spu_detail` (
  `spu_id` bigint(20) NOT NULL COMMENT 'SPU Id',
  `description` text COMMENT '商品描述信息',
  `generic_spec` varchar(2048) NOT NULL DEFAULT '' COMMENT '通用规格键值对 (json格式)',
  `special_spec` varchar(1024) NOT NULL DEFAULT '' COMMENT '特有规格可选值 (json格式)',
  `packing_list` varchar(1024) DEFAULT '' COMMENT '包装清单',
  `after_service` varchar(1024) DEFAULT '' COMMENT '售后服务',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`spu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

这张表中的数据都比较大,为了不影响主表的查询效率我们拆分出这张表。

需要注意的是这两个字段:generic_specspecial_spec

SKU表   sku

CREATE TABLE `tb_sku` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'SKU Id',
  `spu_id` bigint(20) NOT NULL COMMENT 'SPU Id',
  `title` varchar(256) NOT NULL COMMENT '商品标题',
  `images` varchar(1024) DEFAULT '' COMMENT '商品图片 (多个图片用,号分割)',
  `stock` int(8) unsigned DEFAULT '9999' COMMENT '库存',
  `price` bigint(16) NOT NULL DEFAULT '0' COMMENT '销售价格 (单位为分)',
  `indexes` varchar(32) DEFAULT '' COMMENT '特有规格参数在SPU规格模板中对应的下标组合(如1_0_0)',
  `own_spec` varchar(1024) DEFAULT '' COMMENT 'SKU的特有规格参数键值对 (json格式,反序列化时请使用linkedHashMap,保证有序)',
  `enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否有效 (0-无效,1-有效)',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
  PRIMARY KEY (`id`),
  KEY `key_spu_id` (`spu_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27359021564 DEFAULT CHARSET=utf8 COMMENT='sku表,该表表示具体的商品实体,如黑色的 64g的iphone 8'

接下来对SPU表和SKU表字段进行下详细的说明

我们先来看 tb_spu表,这个表应该没有什么多大的问题,就是放一些共有的共有的字段,对cid说明一下吧,为什么设计了三个cid(分类id)字段,直接保存一个分类Id不就可以找到其他的分类Id了吗 ? 这样想是没有问题的,我们主要是为了更好的页面显示才这样设计的,大家也可以自行优化。

然后 tb_spu表 控制商品的上下架、控制商品是否有效,比如一个SKU下的商品如果没有库存那么这个SKU就无效了,而一个SPU是包含多个SKU的,所以设计一个总的标志来标识某个SPU是否有效。

我们之所以把SPU表在分解出一个详情表的原因就是考虑到性能的问题,把一些大字段单独分出来,也就是垂直拆分,这样可以提高数据检索效率。

tb_spu_detail(商品详情表) 我们主要讲解两个字段:

  • generic_spec:通用规格参数数据

  • special_spec:特有规格参数及可选值信息(json格式)

前面讲过 规格参数 与 商品分类 绑定,同一分类的商品 会有一套相同的规格参数 key(规格参数模板),但是这个分类下每个商品的规格参数值都不相同,因此要满足下面几点:

  • 我们有一个规格参数表,跟分类关联,保存的就是某分类下的规格参数模板。
  • 我们还需要一个表,保存某个商品Id,以及和这个商品相关联的规格参数的值(商品_规格参数值_中间表)。
  • 规格参数因为分成了通用规格参数和特有规格参数,因此规格参数值也需要分别与 SPU和SKU关联:1. 通用的规格参数值与SPU关联   2. 特有规格参数值与SKU关联 

但是我们并没有增加新的表,来看下我们的表如何存储这些信息。

generic_spec 字段:

如果要设计一张中间表A,来表示SPU中的通用规格属性的值,至少需要下面的字段:

  • spu_id: 商品Id
  • param_id:规格参数Id
  • param_value: 规格参数的值

我们并没有这么设计,而是把商品的规格参数值,直接保存到 tb_spu_detail (商品详情表) 中,因此这些规格参数关联的商品一目了然,那么上述中间表A 3个属性中的 spu_id 就不需要了,剩下的就是 param_id(规格参数Id) 和 param_value(规格参数的值),两者刚好是 一 一 对应关系,可以组成一个键值对,我们刚好可以用一个json结构来表示。

也就是用 tb_spu_detail表 中的 generic_spec 保存 通用规格参数的值,整体来看:

# tb_spu_detail表中通用属性: generic_spec(spu_id = 2) 与 tb_spec_param 表中的id一一对应  
# json结构 {通用规格参数Id_1:通用规格参数的值_1, 通用规格参数Id_2:通用规格参数的值_2, ...}
{
	"1": "华为",
	"2": "G9青春版(全网通版)",
	"3": 2016,
	"5": 143,
	"6": "陶瓷",
	"7": "Android",
	"8": "骁龙(Snapdragon)",
	"9": "骁龙617(msm8952)",
	"10": "八核",
	"11": 1.5,
	"14": 5.2,
	"15": "1920*1080(FHD)",
	"16": 800,
	"17": 1300,
	"18": 3000
}

json结构,其中都是键值对:

  • key:对应 spec_param(规格参数表)的id,规格参数Id
  • value:对应规格参数的值

special_spec 字段:

我们说SPU中只保存通用规格参数,那么为什么又多出了一个special_spec字段呢?

以手机为例,品牌、操作系统等肯定都是通用规格参数,而内存、颜色等肯定是特有的规格参数。

当你确定了一个SPU,比如小米的:红米4X,因为颜色、内存等特有规格的不同,就会形成多个SKU。

如果把每个SKU的颜色、内存等特有规格都整理出来,就会形成下面的结果:

  • 颜色:[白色,金色,玫瑰金]
  • 内存:[2G,3G]
  • 机身存储:[16GB,32GB]

也就是说,把一个SPU下的每个SKU的特有规格参数值聚合到一起,就是special_spec字段

来看数据格式:

# tb_spu_detail表中特殊属性:special_spec(spu_id = 2) 与 tb_sku表中的id一一对应  
{
	"4": ["白色", "金色", "玫瑰金"],
	"12": ["3GB"],
	"13": ["16GB"]
}

也是json结构:

  • key:规格参数Id
  • value:SPU特有规格数组

那么问题来了,为什么要在SPU中把所有SKU的规格参数聚合起来保存呢?

因为我们需要把商品的所有规格参数都查询出来、展示给用户进行选择,而不是只查询1个SKU的规格参数

比如,商品详情页展示可选的规格参数时:

刚好符合我们的结构,这样页面渲染就非常方便了。

综上所述,SPU与商品规格参数模板的关系如图所示:

SPU表弄清楚了,在讲解SKU表字段的时候就很容易理解了:

  • indexes: 特有规格参数在SPU参数模板中的对应下标组合。
  • own_spec:SKU的特有规格参数键值对(json格式,反序列化时请使用linkedHashMap以保证有序)。
  • enable: 是否有效。

SKU主要就是这3个字段,其他的字段大家看一眼就应该明白了。

own_spec 字段:

own_spec 描述的是SKU特有规格参数键值对(json格式),是一个商品具体的规格参数,看数据:

{
	"4": "白色",
	"12": "3GB",
	"13": "16GB"
}

保存的是特有规格的键值对。

注意special_spec和own_spec两个字段的配合:SPU中的special_spec保存的是“可选项”但不确定具体的值,而SKU中的own_spec保存的就是具体的值

indexes 字段:

特有规格参数在SPU规格模板中的对应下标组合,保存到 indexes 字段。

在SPU表中,已经对特有规格参数及可选项(special_spec字段)进行了保存,结构如下:

# tb_spu_detail表中特殊属性:special_spec(spu_id = 2) 与 tb_sku表中的id一一对应  
{
	"4": ["白色", "金色", "玫瑰金"],
	"12": ["3GB"],
	"13": ["16GB"]
}

把上面的特有参数进行排列组合,就会有三种 :

  • Nova 5,白色,3GB,16GB :0_0_0      —>  规格是:白色_3GB_16GB
  • Nova 5,金色,3GB,16GB :1_0_0      —>  规格是:金色_3GB_16GB
  • Nova 5,玫瑰金,3GB,16GB :2_0_0   —>  规格是:玫瑰金_3GB_16GB

如果在可选项中再添加其他的,排列组合的方式就会更多,这里通过每组可选项的下标进行记录(如 0_0_0),这样可以做到当用户点击哪一个可选项,我们就可以快速定位到SKU,我们把这种 “下标组合” 就记录在 indexes 字段。

enable字段就是控制具体的一个商品的规格是否有效。


总结:

我们设计了哪几张表,有什么关系

  • 分类表: tb_category
  • 品牌表: tb_brand
  • 分类品牌表:tb_category_brand
  • 规格组表: tb_spec_group
  • 规格参数表:tb_spec_param
  • SPU表: tb_spu
  • SPU详情表: tb_spu_detail
  • SKU表: tb_sku

关系:

  • 一个分类有多个品牌,一个品牌属于多个分类,所以是多对多
  • 一个分类有多个规格组,一个规格组有多个规格参数,所以是一对多
  • 一个分类下有多个SPU,所以是一对多
  • 一个品牌下有多个SPU,所以是一对多
  • 一个SPU下有多个SKU,所以是一对多

The End ~

————————————————
版权声明:本文为CSDN博主「一个不懂技术的人」的原创文章,遵循CC 4.0 BY-SA版权协议。
原文链接:https://blog.csdn.net/weixin_42437102/article/details/106825140

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值