MySQL数据库——案例:电子商务网站设计

MySQL数据库 专栏收录该内容
11 篇文章 3 订阅


在了解数据库设计的基本流程、规范以后,为了学以致用,本节将以电子商务网站为例,演示如何进行数据库设计。通过实际操作,加深对数据库设计的理解。

1、需求分析

电子商务网站是一种在互联网上开展电子商务的平台,常见的电子商务网站有淘宝、天猫、京东、亚马逊等。一般来说,电子商务网站最基本的功能是在线购物,它分为前台和后台,后台面向网站的运营人员,用于录人数据,前台面向访问网站的用户,用于选购商品。下面通过表1列举电子商务网站中的一些常见需求。

表1 电子商务网站需求说明
在这里插入图片描述

表1中列举的需求非常多,但对于初学者来说,此时并不需要花费大量的时间研究这些商业领域的需求,最重要的是掌握解决问题的方法。因此,本节仅选取一些典型需求(带有*标注)进行详细讲解。有余力的读者可以尝试解决其他需求。

由于电子商务行业竞争激烈、需求变化快,往往对网站的开发时间要求比较严格,希望网站能尽早上线。对于这样的需求,可以采用迭代式开发,先追求小而精,将核心功能优先完成,为后期的扩展预留空间,然后再通过版本迭代逐渐发展成大而全。

在设计数据库时,考虑到需求将来可能会发生变化的情况,应设计一个尽量能够适应需求变化的数据库,其关键点如下。

(1) 避免数据经常发生变化。将数据保存到数据库中后,数据是不会变的,只有用户对数据进行修改时,数据才会发生变化。在设计数据库时,应尽量保存不变的数据,以减少修改数据带来的开销。例如,在设计用户表时一般会保存出生日期而不是年龄,这是因为利用出生日期和当前日期可以推算出年龄,而若保存年龄,数据每一年都需要发生一次改变。

在实际开发中,经常会遇到一些数据被大量访问,而该数据必须经过复杂的运算才能够获得的情况。例如,在网站首页显示销量排名前10的商品,需要统计出所有商品的销量并降序排列,然后取出前10条记录。当有大量用户同时访问首页时,就会给数据库带来极大的负担,导致页面打开缓慢。为此,可以利用Memcached、Redis等技术对热门数据进行缓存,以减少数据库的查询次数。读者可以查询相关资料了解这些技术。

(2) 避免经常修改表结构。表结构的修改包括字段的增减、数据类型和约束的修改等。对于已经上线的项目,修改表结构可能会导致服务暂停,如果有更好的方案,则尽量避免修改表结构。例如,在网站首页中增加一个显示推荐商品的功能时,不必在商品表中增加一个“推荐”字段,而是专门创建一个“推荐商品”表。其目的是将功能数据与商品数据分离。原因是商品数据一般不会发生变化,而功能数据往往会随着功能的增加或减少而经常发生变化。“推荐商品”只是一个附加功能,应尽可能减少其对商品数据产生的影响。

(3) 尽可能详细地记录日志。利用日志记录数据的变化,可以为将来的功能增加提供数据基础。例如,当网站用户的账号被盗时,为了验明真实情况,需要确定账号被盗取的时间、登录的IP地址,以及充值、消费、订单等数据是否发生过变化。若没有记录日志,则难以追溯。

(4) 避免删除数据。对于已经上线的网站,删除数据是非常敏感的操作,很有可能带来一些始料未及的后果。例如,用户因误操作删除了订单,希望恢复订单,需要在项目中增加.订单回收站功能。若数据库中的订单记录已被删除,即使增加了回收站功能,订单也无法恢复。因此,在设计数据库时,应考虑数据既可以被删除,又可以被恢复。例如,在订单表中增加一个“是否删除”的字段,用来标识记录是否被删除。当查询订单时,通过WHERE获取未被删除的订单,当查询订单回收站时,通过WHERE获取已删除的订单

2、准备工作

在MySQL中创建一个shop数据库,用来保存电子商务网站中的数据。在创建数据库后,使用USEshop选择数据库,具体SQL语句如下。

mysql> CREATE DATABASE shop;
Query OK, 1 row affected (0.00 sec)
mysql> USE shop;
Database changed

在对数据表命名时,为了更好地区分项目,为所有的数据表加上“sh_”前缀。例如,商品表命名为“sh_goods”。

小提示:
在实际开发中,使用各种编程语言编写应用程序访问数据库时,最常见的问题是没有对用户输入的数据进行处理,直接使用字符串拼接到SQL中,这样会导致用户输入的一些特殊字符(如单引号、反斜线、百分号等)被解析,破坏了原有SQL的语义,出现SQL注入等安全问题。因此,在编写应用程序时,一定要对特殊字符进行转义,或者借助一些库或框架来完成处理。

3、商品分类表

商品分类表用于保存分类名称、分类排序是否显示等信息,并要求支持如图2所示的多级分类嵌套。
在这里插入图片描述
图2 分类结构图

在图2中,商品分类是树形结构,父分类和子分类是一对多的关系。接下来通过表2展示商品分类表的具体结构。

表2 商品分类表(sh_goods_category)
在这里插入图片描述
在表2中设计的商品分类表sh_goods_category 共有7个字段,具体说明如下。

  • 分类id,主键,使用无符号整型存储,自动增长。
  • 上级分类id:保存上级分类的id,若值为0,表示上级分类是根节点。
  • 名称,长度在100个字符以内。
  • 排序:用于对同级分类进行排序,按照从小到大的顺序排列。
  • 是否显示:0表示不显示,1表示显示。
  • 创建时间:该分类被插入时的时间戳,后台使用。
  • 更新时间:该分类的最后一次修改的时间戳,后台使用。

小提示:
(1)对于is_show字段,其数据类型选择TINYINT而不是ENUM,这是考虑到需求将来有可能会发生变化,ENMU类型在增加枚举值时需要修改表结构,而TINYINT类型不需要修改表结构。
(2)如果父分类的is_show值为0,则该分类和它的子分类都不会显示。子分类必须满足自身is_show和父分类is_show都为1时才会显示。
(3)对于create_time和update_time字段,其数据类型选择INT而不是TIMESTAMP,这是因为应用程序中习惯使用时间戳来保存时间,直接保存为INT类型会更加方便。

下面根据表2所示的表结构,创建商品分类表,具体SQL语句如下。

CREATE TABLE sh_goods_category (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '分类id',
parent_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '上级分类id',
name VARCHAR(100) NOT NULL DEFAULT '' COMMENT '名称',
sort INT NOT NULL DEFAULT 0 COMMENT '排序',
is_show TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否显示',
create_time TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间',
update_time TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

商品分类表创建完成后,添加测试数据,具体SQL语句如下。

INSERT INTO sh_goods_category (id, parent_id, name) VALUES
(1, 0, '办公'), (2, 1, '耗材'), (3, 2, '文具'),
(4, 0, '电子产品'), (5, 4, '通讯'), (6, 5, '手机'),
(7, 4, '影音'), (8, 7, '音箱'), (9, 7, '耳机'),
(10, 4, '电脑'), (11, 10, '台式电脑'), (12, 10, '笔记本'),
(13, 0, '服装'), (14, 13, '女装'), (15, 14, '风衣'), (16, 14, '毛衣');

在上述SQL语句中,测试数据一共包含16条分类记录,层次关系如下。

办公-耗材-文具		电子产品-通讯-手机 		电子产品-影音-音箱
电子产品-影音-耳机	电子产品一电脑-台式电脑		电子产品一电脑-笔记本
服装-女装-风衣		服装-女装-毛衣

4、商品表

商品分类与商品是一对多的联系一个分类中有多件商品。商品表的具体结构如表3所示。
表3 商品表(sh_goods)
在这里插入图片描述

在表3中设计的商品表sh_goods共有21个字段,具体说明如下。
 商品id:主键,使用无符号整型存储,自动增长。
 分类id:商品所属分类,使用无符号整型存储,自动增长。
 SPU id:标准化产品单元id(具体会在后面讲解)。
 编号:长度在20个字符以内。
 名称:长度在120个字符以内。
 关键词:用于在搜索和浏览列表时更准确的找到该商品。
 图片:用于在商品列表中显示商品的预览图,保存图片路径。
 提示:用于醒目的显示该商品的提示信息,如促销信息、推荐语等。
 描述:用于通过简短的文字描述商品的基本信息。
 详情:用于描述商品的详细信息。
 评分:用户购买商品后的评分(1~5),此处为平均分,主要用于排序。
 价格、库存:商品的价格和库存。
 是否上架、是否删除、是否包邮:0表示是,1表示否。
 销量计数、评论计数:商品的销量和评论数量,主要用于排序。
 上架时间:商品的上架时间,主要用于排序。
 创建时间:该商品被插入时的时间戳,后台使用。
 更新时间:该商品最后一次修改的时间戳,后台使用。

小提示:
(1)对于商品编号,若没有特殊要求,一般情况下使用商品id作为编号。但考虑到将来有可能更换另外一套规则来管理编号,因此这里预留了一个编号字段。
(2)
由于商品分类是多级嵌套结构,一般来说,商品所属的分类应该是叶子节点的分类。如果现有分类不能满足需求,可以增加一个名称为“其他”的分类。
(3)用户上传的图片等文件,一般是由Web服务器来管理的,数据库中只保存它们的引用路径。

下面根据表3所示的表结构,创建商品表,对应的SQL语句如下。

CREATE TABLE sh_goods (
  id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '商品id',
  category_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '分类id',
  spu_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'SPU id',
  sn VARCHAR(20) NOT NULL DEFAULT '' COMMENT '编号',
  name VARCHAR(120) NOT NULL DEFAULT '' COMMENT '名称',
  keyword VARCHAR(255) NOT NULL DEFAULT '' COMMENT '关键词',
  picture VARCHAR(255) NOT NULL DEFAULT '' COMMENT '图片',
  tips VARCHAR(255) NOT NULL DEFAULT '' COMMENT '提示',
  description VARCHAR(255) NOT NULL DEFAULT '' COMMENT '描述',
  content TEXT NOT NULL COMMENT '详情',
  price DECIMAL(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '价格',
  stock INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '库存',
  score DECIMAL(3, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '评分',
  is_on_sale TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否上架',
  is_del TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否删除',
  is_free_shipping TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否包邮',
  sell_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '销量计数',
  comment_count INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '评论计数',
  on_sale_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '上架时间',
  create_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间',
  update_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建商品表后,插人测试数据,具体SQL语句如下。

INSERT INTO sh_goods (id, category_id, name, keyword, content, price, 
stock, score, comment_count) VALUES
(1, 3, '2B铅笔', '文具', '考试专用', 0.5, 500, 4.9, 40000),
(2, 3, '钢笔', '文具', '练字必不可少', 15, 300, 3.9, 500),
(3, 3, '碳素笔', '文具', '平时使用', 1, 500, 5, 98000),
(4, 12, '超薄笔记本', '电子产品', '轻小便携', 5999, 0, 2.5, 200),
(5, 6, '智能手机', '电子产品', '人人必备', 1999, 0, 5, 98000),
(6, 8, '桌面音箱', '电子产品', '扩音装备', 69, 750, 4.5, 1000),
(7, 9, '头戴耳机', '电子产品', '独享个人世界', 109, 0, 3.9, 500),
(8, 10, '办公电脑', '电子产品', '适合办公', 2000, 0, 4.8, 6000),
(9, 15, '收腰风衣', '服装', '春节潮流单品', 299, 0, 4.9, 40000),
(10, 16, '薄毛衣', '服装', '居家旅行必备', 48, 0, 4.8, 98000);

5、商品规格表

在电子商务网站中有SPU(Standard Product Unit,标准化产品单元)和SKU(Stock KeepingUnit,库存量单位)的概念。它们可以简单理解为看待商品的两种不同的角度,SPU从信息聚合的角度看待商品,SKU从库存管理的角度看待商品。例如,一款饮料有500ml和750ml两种规格,对应的库存和价格不同,它们是不同的SKU,在sh_goods表中每个SKU商品是一条商品记录。在店铺中展示商品时,如果按照SKU进行展示,会出现大量冗余的信息(同一款饮料因为规格不同重复出现),不利于顾客挑选商品,因此店铺通常会将相同款式的商品合并成SPU,如图2所示。
在这里插入图片描述
图2 商品SPU与SKU

在图2中,整个页面可以理解为一件SPU商品,在页面中可以切换500ml和750ml,这两种规格的SKU商品,当切换后,价格和库存也会发生变化。
需要注意的是,图4-6演示的商品规格只有一个维度,即容量,而有些商品的规格可能有多个维度,如手机的规格可以分为网络、颜色、内存3个维度,如图3所示。

在这里插入图片描述
图3 手机规格

由此可见,不同商品的规格维度不固定,不同维度的规格项的数量也不固定。为了满足这种需求,一般需要如下4张表才能够实现。

  • sh_goods_spu(id, name)
  • sh_goods_spec(id, name)
  • sh_goods_spec_item(id, spec_id, name, description, picture)
  • sh_goods_spec_set(goods_id, spec_item_id)

在上述表中,sh_goods_spu保存SPU的id和名称,一个SPU包含多件商品,sh_goods中的spu_id字段就表示该商品所属的SPU;sh_goods_spec保存规格,如“网络、颜色、内存”;sh_goods_specitem保存规格项,如“移动、电信”,一个规格包含多个规格项;sh_goods_spec_set保存商品的规格项组合,如“电信-白色-4GB”(实际保存的是id)。
接下来通过表4~表7展示上述4张表的表结构。

表4 商品spu表(sh_goods_spu)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENTSPU id
nameVARCHAR(80) NOT NULL DEFAULT ‘’SPU名称

表5 商品规格表(sh_goods_spec)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT规格id
nameVARCHAR(80) NOT NULL DEFAULT ‘’规格名称

表6 商品规格项表(sh_goods_spec_item)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT规格id
nameVARCHAR(80) NOT NULL DEFAULT ‘’规格名称

表7 商品规格项组合表(sh_goods_spec_set)

字段名数据类型和约束说明
goods_idINT UNSIGNED NOT NULL DEFAULT 0SKU id
spec_item_idINT UNSIGNED NOT NULL DEFAULT 0规格id

下面根据表4~表7所示的表结构,创建上述4张表,对应的SQL语句如下。

# 商品SPU表
CREATE TABLE sh_goods_spu (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'SPU id',
name VARCHAR(80) NOT NULL DEFAULT '' COMMENT 'SPU名称'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 商品规格表
CREATE TABLE sh_goods_spec (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '规格id',
name VARCHAR(80) NOT NULL DEFAULT '' COMMENT '规格名称'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 商品规格项表
CREATE TABLE sh_goods_spec_item (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '规格项id',
spec_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '规格id',
name VARCHAR(80) NOT NULL DEFAULT '' COMMENT '名称',
description VARCHAR(255) NOT NULL DEFAULT '' COMMENT '描述',
picture VARCHAR(255) NOT NULL DEFAULT '' COMMENT '可选图'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 商品规格组合表
CREATE TABLE sh_goods_spec_set (
goods_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'SKU id',
spec_item_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '规格id'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据表创建完成后,为上述4张表添加测试数据;具体SQL语句如下。

INSERT INTO sh_goods_spu (id, name) VALUES
(1, '新款智能手机');
INSERT INTO sh_goods_spec (id, name) VALUES
(1, '网络'), (2, '颜色'), (3, '内存');
INSERT INTO sh_goods_spec_item (id, spec_id, name) VALUES
(1, 1, '移动'), (2, 1, '电信'), (3, 2, '白色'), 
(4, 2, '黑色'), (5, 3, '4G'), (6, 3, '6G');
INSERT INTO sh_goods_spec_set (goods_id, spec_item_id) VALUES
(5, 2), (5, 3), (5, 5);

在上述测试数据中,goods_id为5的商品(智能手机)的规格项有“电信”“白色”和“4GB”,表示该商品的规格为“网络:电信,颜色:白色,内存: 4GB”,该商品和其他规格的商品组成了一个SPU,即sh_goods_spu表中id为1的“新款智能手机”。

需要注意的是,在查询商品列表时,如果直接查询sh_goods表中的记录,会导致一个SPU中的多个SKU商品都显示在列表中,占用列表的空间,不利于挑选商品。为了解决这个问题,可以按照表中的spu_id字段去除重复记录,只保留一条商品记录即可。

小提示:
在实际应用中,考虑到多张表的查询操作过于复杂,有时会通过逆规范化的设计,增加一些冗余字段以方便查询。例如,在sh_goods_spu表中增加一个字段,将每个SPU相关的规格、规格项、规格组合以JSON格式编码后保存,从而简化查询。

6、商品属性表

商品属性主要有两个作用,一个是在商品展示页面中显示商品属性表格,一个是在商品列表页面中筛选商品,分别如图4和图5所示。

在这里插入图片描述
图4 商品属性

在这里插入图片描述
图5 商品筛选

需要注意的是,图4-8和图4-9中的属性是针对手机分类的商品设计的,而本项目有多种商品分类,应为不同分类的商品设计不同的属性模板。
为了满足上述需求,可以通过如下4张表来实现。

  • sh_goods_attr(id, parent_id, category_id, name, sort)
  • sh_goods_attr_value(id, goods_id, attr_id, attr_value)
  • sh_goods_selector(id, parent_id, category_id, name, sort)
  • sh_goods_selector_value(id, goods_id, selector_id, selector_value)

在上述表中,sh_ goods_ attr 保存商品属性,一般有两个层级,第1级如“主体、基本信息、主芯片”,第2级如“上市年份、上市月份、机身颜色”;sh_goods_attr_value保存商品的属性值;sh_goods_selector 保存筛选条件,一般有2~3级,2级如“机身内存——8GB以下”,3级如“高级选项-网络-电信”;sh_goods_selector_value保存商品的筛选值。

严格来说,sh_goods_attr和sh_goods_selector表中的category_id字段存在冗余,因为商品属性存在层级关系,当通过category_id查找商品属性时,首先找到父属性,然后通过父属性找到子属性,此时子属性的category_id是没有意义的,它的值和父属性的category_id字段相同。若要消除冗余,应将父属性和子属性拆分成两张表,但这里为了简化操作,没有进行拆分,在实际开发中应避免这个冗余字段出现问题。

接下来通过表8~表11展示上述4张表的表结构。
表8 商品属性表(sh_goods_attr)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT属性id
parent_idINT UNSIGNED NOT NULL DEFAULT 0上级属性id
category_idINT UNSIGNED NOT NULL DEFAULT 0商品分类id
nameVARCHAR(80) NOT NULL DEFAULT ‘’名称
sortINT NOT NULL DEFAULT 0排序

表9 商品属性值表(sh_goods_attr_value)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT属性值id
goods_idINT UNSIGNED NOT NULL DEFAULT 0商品id
attr_idINT UNSIGNED NOT NULL DEFAULT 0属性id
attr_valueVARCHAR(80) NOT NULL DEFAULT ‘’属性值

表10 商品筛选表(sh_goods_selector)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT筛选id
parent_idINT UNSIGNED NOT NULL DEFAULT 0上级筛选id
category_idINT UNSIGNED NOT NULL DEFAULT 0商品分类id
nameVARCHAR(80) NOT NULL DEFAULT ‘’名称
sortINT NOT NULL DEFAULT 0排序

表11 商品筛选值表(sh_goods_selector_value)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT筛选值id
goods_idINT UNSIGNED NOT NULL DEFAULT 0商品id
selector_idINT UNSIGNED NOT NULL DEFAULT 0筛选id
selector_valueVARCHAR(80) NOT NULL DEFAULT ‘’筛选值

下面根据表4-8~表4-11所示的表结构,创建上述4张表对应的SQL语句如下。

# 商品属性表
CREATE TABLE sh_goods_attr (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '属性id',
parent_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '上级属性id',
category_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '商品分类id',
name VARCHAR(80) NOT NULL DEFAULT '' COMMENT '名称',
sort INT NOT NULL DEFAULT 0 COMMENT '排序'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 商品属性值表
CREATE TABLE sh_goods_attr_value (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '属性值id',
goods_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '商品id',
attr_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '属性id',
attr_value VARCHAR(80) NOT NULL DEFAULT '' COMMENT '属性值'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 商品筛选表
CREATE TABLE sh_goods_selector (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '筛选id',
parent_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '上级筛选id',
category_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '商品分类id',
name VARCHAR(80) NOT NULL DEFAULT '' COMMENT '名称',
sort INT NOT NULL DEFAULT 0 COMMENT '排序'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 商品筛选值表
CREATE TABLE sh_goods_selector_value (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '筛选值id',
goods_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '商品id',
selector_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '筛选id',
selector_value VARCHAR(80) NOT NULL DEFAULT '' COMMENT '筛选值'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

完成数据表的创建后,为上述4张表添加测试数据,具体SQL语句如下。

INSERT INTO sh_goods_attr VALUES
(1, 0, 6, '基本信息', 0), (2, 1, 6, '机身颜色', 0),(3, 1, 6, '输入方式', 1),
 (4, 1, 6, '操作系统', 2),(5, 0, 6, '屏幕', 1), (6, 5, 6, '屏幕尺寸', 0), 
 (7, 5, 6, '屏幕材质', 1),(8, 5, 6, '分辨率', 2), (9, 0, 6, '摄像头', 2),
(10, 9, 6, '前置摄像头', 0), (11, 9, 6, '后置摄像头', 1),(12, 0, 6, '电池信息', 3),
 (13, 12, 6, '电池容量', 0),(14, 12, 6, '是否可拆卸', 1);

INSERT INTO sh_goods_attr_value VALUES
(1, 5, 2, '黑色'), (2, 5, 3, '触摸屏'), (3, 5, 4, 'Android'),(4, 5, 6, '5.5寸'), (5, 5, 7, 'IPS'),
 (6, 5, 8, '1920*1080'),(7, 5, 10, '1600万'), (8, 5, 11, '800万'),(9, 5, 13, '3500mAh'),
 (10, 5, 14, '否');

小提示:
若希望筛选范围是一个区间(如手机的存储容量有1G、2G、4G等选择),有两种实现思路,一种是使用描述范围(如“2G以上”“1G~2G”)作为筛选项,另一种是在sh_goods_selector_value表中增加一个数字类型的字段,专门保存数字类型的属性值,在查询时使用大于、小于运算符来表示一个区间。

7、用户表

由于网站分为前后台,这里所说的用户是指前台用户,也就是网站的访客通过注册账号成为网站的用户。一般来说,数据库中的用户表包含两类信息,一类是登录信息,即账号和密码,账号通常是编号、用户名、邮箱或手机号等具有唯一性的值;另一类是用户的个人信息,如姓名、性别、出生年月、所在地等。

接下来通过表12展示用户表的具体结构。
表12 用户表(sh_user)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT用户id
nameVARCHAR(100) NOT NULL UNIQUE DEFAULT ‘’用户名
passwordVARCHAR(255) NOT NULL DEFAULT ‘’密码
saltCHAR(32) NOT NULL DEFAULT ‘’密码盐
emailVARCHAR(128) NOT NULL DEFAULT ‘’邮箱
mobileCHAR(11) NOT NULL DEFAULT ‘’手机号
levelTINYINT UNSIGNED NOT NULL DEFAULT 0用户级别
moneyDECIMAL(10, 2) UNSIGNED NOT NULL DEFAULT 0金额
genderTINYINT UNSIGNED NOT NULL DEFAULT 0性别
qqVARCHAR(20) NOT NULL DEFAULT ‘’QQ
is_activeTINYINT UNSIGNED NOT NULL DEFAULT 0是否激活
reg_timeINT UNSIGNED NOT NULL DEFAULT 0注册时间
create_timeINT UNSIGNED NOT NULL DEFAULT 0创建时间
update_timeINT UNSIGNED NOT NULL DEFAULT 0更新时间

下面根据表4-23所示的表结构,完成用户表的创建,对应的SQL语句如下。

CREATE TABLE sh_user (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '用户id',
name VARCHAR(100) NOT NULL UNIQUE DEFAULT '' COMMENT '用户名',
password VARCHAR(255) NOT NULL DEFAULT '' COMMENT '密码',
salt CHAR(32) NOT NULL DEFAULT '' COMMENT '密码盐',
email VARCHAR(128) NOT NULL DEFAULT '' COMMENT '邮箱',
mobile CHAR(11) NOT NULL DEFAULT '' COMMENT '手机号',
level TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户级别',
money DECIMAL(10, 2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '金额',
gender TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '性别',
qq VARCHAR(20) NOT NULL DEFAULT '' COMMENT 'QQ',
is_active TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否激活',
reg_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '注册时间',
create_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间',
update_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

需要注意的是,考虑到Web项目的安全性,应对用户的密码进行加密,不能明文存储,否则一旦发生数据泄露,将会给网站带来极大的损失。密码的加密方式有很多,比较常见的是MD5加密算法,下面通过具体SQL语句进行演示。

mysql> SELECT MD5(CONCAT(MD5('password'), 'salt'));
+--------------------------------------+
| MD5(CONCAT(MD5('password'), 'salt')) |
+--------------------------------------+
| d514dee5e76bbb718084294c835f312c     |
+--------------------------------------+
1 row in set (0.00 sec)

在上述SQL语句中,MD5(‘password’)表示使用MD5()函数对password字符串进行MD5(消息摘要算法第五版)运算,运算的结果是一个字符串,由32个字符构成。CONCAT()函数用于字符串拼接,此处是在MD5(‘password’)运算获得的字符串基础上拼接了salt字.符串。最后,再次使用MD5()函数对拼接结果进行一次MD5运算。

MD5算法具有不可逆性,通过计算后的结果将无法还原成原文,而对于完全相同的内容,其计算后的结果也是相同的,因此MD5算法经常用于密码的存储。但这种方式也有缺点,如果将世界上所有的密码与计算结果全部存储起来进行检索,则密码就会被逆向查找出来。为了解决这个问题,通常会为每个用户生成一个salt( 盐),用于在对密码进行MD5计算时加入salt,以提高密码加密的复杂度,使密码更不容易被破解。

用户表创建完成后,为用户表添加测试数据,具体SQL语句如下。

INSERT INTO sh_user (id, name, password, salt, money, is_active)  
VALUES
(1, 'Alex', MD5(CONCAT(MD5('123'), 'salt1')), 'salt1', 1000, 1),
(2, 'Bill', MD5(CONCAT(MD5('123'), 'salt2')), 'salt2', 1000, 1);

在上述测试数据中,password字段对密码进行了加密,其中123是密码原文,Alex和Bill的密码相同,但salt不同,所以密码的加密结果也不同。在实际开发中,读者可以借助一些函数生成一个随机字符串,作为salt使用,如MD5(RAND())。
接下来查看sh_ user 表中的记录,观察密码加密结果,如下所示。

mysql> SELECT id, name, password, salt FROM sh_user;
+----+------+----------------------------------+-------+
| id | name | password                         | salt  |
+----+------+----------------------------------+-------+
|  1 | Alex | a3a5b6c3c00b37a4c53f82d1ce8bb86c | salt1 |
|  2 | Bill | 8d890cf2ffd7af2c367537c0d6ae99df | salt2 |
+----+------+----------------------------------+-------+
2 rows in set (0.00 sec)

8、评论表

当用户购买商品后,可以发表评论。对于已经发表的评论,可以进行追加。商品评论表的具体结构如表13所示。
表13 商品评论表(sh_goods_comment)

字段名数据类型和约束说明
idINT UNSIGNED PRIMARY KEY AUTO_INCREMENT评论id
parent_idINT UNSIGNED NOT NULL DEFAULT 0上级评论id
user_idINT UNSIGNED NOT NULL DEFAULT 0用户id
goods_idINT UNSIGNED NOT NULL DEFAULT 0商品id
contentTEXT NOT NULL评论内容
is_staffTINYINT UNSIGNED NOT NULL DEFAULT 0工作人员
is_showTINYINT UNSIGNED NOT NULL DEFAULT 0是否显示
is_delTINYINT UNSIGNED NOT NULL DEFAULT 0是否删除
create_timeINT UNSIGNED NOT NULL DEFAULT 0创建时间
update_timeINT UNSIGNED NOT NULL DEFAULT 0更新时间

在表13中,is_staff字段表示该评论是否为网站的后台用户(即工作人员)发表的,用于工作人员回复用户的评论、解答疑问等。

下面根据表13的结构,创建商品评论表,对应的SQL语句如下。

CREATE TABLE sh_goods_comment (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '评论id',
parent_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '上级评论id',
user_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户id',
goods_id INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '商品id',
content TEXT NOT NULL COMMENT '评论内容',
is_staff TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否为工作人员',
is_show TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否显示',
is_del TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否删除',
create_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间',
update_time INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据表创建完成后,为商品评论表添加测试数据,具体SQL语句如下。

INSERT INTO `sh_goods_comment` (id, user_id, goods_id, content,
is_show, create_time) VALUES
(1, 1, 8, '好', 0, 1510070400),
(2, 2, 10, '不错', 1, 1512230400),
(3, 3, 9, '满意', 1, 1514563200),
(4, 4, 4, '携带方便', 1, 1516291200),
(5, 4, 7, '中低音效果特别棒', 1, 1516291200),
(6, 5, 8, '卡机', 1, 1516550400),	
(7, 6, 5, '黑夜拍照也清晰', 1, 1518624000),
(8, 7, 9, '掉色、有线头', 0, 1520006400),
(9, 4, 9, '还行', 1, 1522857600),
(10, 8, 9, '特别彰显气质', 1,1523808000);

超全面的测试IT技术课程,0元立即加入学习!有需要的朋友戳:


腾讯课堂测试技术学习地址

欢迎转载,但未经作者同意请保留此段声明,并在文章页面明显位置给出原文链接。

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页

打赏作者

sem00000

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值