数据库设计实例---学习数据库最重要的应用之一

一、引言【可忽略】

        在学习“数据库系统概述”这门课程时,我一直很好奇,这样一门必修课,究竟教会了我什么呢?

        由于下课后,,没有拓展自己的眼界,上课时又局限于课堂上老师的讲课水平,我一直不理解这门课的意义。

        我在其中学会了什么呢?坦言,有不少新名词:

        比如范式、事务、码、集合运算等等。

        可是,在实际应用中,我发现课堂上讲到的,只有我早就学过的SQL语句会真正使用。

        也就是增删改查,SELECT、DELETE、UPDATE和INSERT四个语句。

        后来从需求文档开始开发一个项目,我也是懵懵懂懂,由于队友提前把数据库建好了,我并没有学到建立数据库的知识。

        也是某次契机,面试时面试官询问:你如何设计这个数据库的?

        于是回去我恶补了一下,花了半个星期,终于把我学过的知识联系起来。

        数据库设计:是比使用SQL语句更重要的知识,因为使用SQL语句的基础,先是有一个数据库,有一些表。

二、数据库建立的六个步骤和笼统的对应目标

        正如解数学题一样,数据库的建立也有其流程,如下:

第一步,需求分析。

        该步骤从实际出发,成果物是一份需求文档【专业名词叫“用户需求规格说明书”】。

        重点在于,拿到用户的数据需求和数据处理需求。【简单地说,就是你要存什么数据(比如一个学生类),以及你要对这些数据做什么处理?(比如增删改查)】

        在更实际的开发中,我们可能会涉及性能需求、安全需求,在此不赘述。

第二步,概念结构设计

        这个词语很难理解,我认为可以叫做“模型设计”。

        因为这一步的目标是,设计出一个“模型”,什么样的模型呢?

        E-R实体联系模型。

        这个模型,定义了这个数据库中,包含的实体、实体拥有的属性和实体之间的联系,有一些特殊实体,可能还会在联系中,加入一些特殊的约束。

第三步,逻辑结构设计

        这个词语也不太好理解,你可以认为,这里的“逻辑”是指,从实体模型,转化为关系模型,抽象了一个层面,所以叫做“逻辑”设计。

        这一步的目标,是得到可以作为数据库的关系模型。【关系模型的意思后面再讲】

        我们拿到E-R模型后,根据一些转换原则,很容易拿到关系模型,但是不是所有关系模型,都能当数据库使用。

        至少经过3步范式,才能设计出不容易出问题、面对异常处理比较好用的关系模型。

第四步,物理结构设计

        这一步不是我们考虑的,更多是操作系统开发商和数据库开发商考虑的。

第五步,数据库的部署和测试

        没什么好说的。

第六步,数据库的运维

        无。

        我们可以发现,从0到1的数据库开发,重点在于前3步。下面,我用一个实例来讲解如何进行。

三、客户需求【从0开始,可忽略本节,直接看末尾】

        小明是个游戏开发人员,一直苦于如何将内购模式,加入自己的游戏。

        有一天,他发现某团外卖平台的订单结构非常好,但是自己不熟悉如何设计,花钱请你帮忙开发。

        你询问需求。

        小明说:“我们的客户,每一个都是独一无二的,有属于自己的游戏ID、游戏名字、密码和手机号、邮箱等等。”

        他又说:“某团的结构,也是这样,所以我们应该能互相转换。”

        好,我们有了第一个实体,这是一份客户表。

        你继续询问。

        小明说:“内购模式,最大的问题是如何处理订单,因为游戏的装备很多,如果玩家A,一次性购买20个超级戒指、20瓶恢复药水。”

        他顿了顿,说道:“我也学过一点数据库。对于上述要求,如果在一张表里存储,要不就用一个集合存储这些装备信息,要不就得在一张表,存储40个信息,可是玩家ID是主键,一张表里不可能有40个相同ID,更何况,这么做信息冗余很多,查找起来也麻烦。”

        “所以,我想要一个独立的订单,它关联着用户。”

        好,我们有了第二个实体,这是个订单表,也许它和客户表有联系,不过没有关系,目前不在乎。

        游戏里有什么戒指、恢复药水的装备,以后可能还会增加一些装备,如果在订单表里,把所有装备都定义上,并且用另一列,管理它们的购买个数。【类似于HashMap的key、value思想】

        可行,不过冗余较大。

        你继续询问。

        “没了。”

        就此,你大概能知道需要那些东西。

        ------从这里开始看

        我们的问题是,如何将用户、订单和装备联系起来。

        考虑这样的场景:玩家A,买了3个戒指、4瓶药水、100个卷轴,如何存储起来。

        第一,一个用户表应该是必要的,至少要存储用户信息。

        第二,订单表好像也需要,不过订单表里的内容,也许需要斟酌。

四、需求分析【真正分析】

        由上面的场景,我们对每个实体分析一下数据需求和数据处理需求。

        用户表基本没什么问题,为了一个订单表,把用户表全改了,是没必要的。

        玩家A,可能昨天买了一单,今天买了3单,A与订单之间,明显是1对多的关系。

        一个玩家,可以拥有n个订单。一个订单,只能属于一个玩家。

        订单和装备呢?

        用一张装备表,存储装备是个不错的想法,可是订单可能有n个装备,干脆用订单表存储所有的装备?

        问题是:这样想要拓展装备,很麻烦。

        当我们为这样的问题犹豫时,记住2个原则

        1.订单涉及的装备明显是个变量,一个变量作为表里的一个属性,是非常危险的。

        2.从关系的角度考虑。

        也许我们可以用什么东西,表示订单涉及的装备。

        订单和装备,明显是多对多的关系,一个订单,可能有n种装备,一种装备,可能属于m个订单。

        所以,必须独立出来。

第一,用户表

        数据需求:用户ID、用户名、密码、邮箱、手机。【也许还有订单?或者一些描述信息?随便】

        数据操作需求:注册(增加)、修改密码(修改)、登录时查看表(查找)、用户注销(也许不会实际删除,但起码要表示一下,提供一个接口)

第二,订单表

        数据需求:可能有订单号ID、订单名字、订单描述、订单价格。

        数据操作需求:增删改查。

第三,装备表

        数据需求:装备号ID、装备名、装备描述、装备价格?【我不确定】

        数据操作需求:增删改查。

五、概念结构设计

        由上面的需求文档,画E-R实体联系模型。

        这一步,主要体现了实体之间不是孤立存在的,而是有联系的。

        这一步,有3个知识点:

        1.有几张表,就画几个实体。

        2.实体中的属性,就按数据需求画,如有增加,可临时增加。【当然,多人开发需要请示】

        3.实体间的联系要画出来。(即1对n、n对m)

        E-R图如下:

        疑问:

        有的同学可能说了:奇怪,需求文档没有用户和装备之间的联系啊?你演我?

        确实,我刚分析的时候也没有,也是刚知道。

六、逻辑结构设计

        将E-R图转化为关系模型,其实就是把实体转成表,只需遵守3个原则。

        【注:这是在只有2元联系的E-R图适用,3元模型大差不差,不过尽量把3元模型转化为2元,否则不好用】

        第一,1对1的联系,如A:B=1:1,则随意在一张表里,加入另一张表的主键,作为外键【比如在A表中,加入B的主键BID,此时,A表中的BID就是A表的外键】

        第二,1对n的联系,如A:B=1:n,在n端表,加入1端表的主键,使该主键成为表外键。【即B表中,加入A表主键AID,则B表的外键是AID】

        第三,n对m的联系,如A:B=n:m,则要把这个联系抽出,独立成一张新表X,使X拥有A、B两表的主键,并且有主外键要求。X的外键是AID或BID,X的主键是AID并BID。

        那么,本题转换为:

        用户表(ID,用户名,密码,手机号,邮箱)

        订单表(ID,订单名,价格,描述,用户ID)

        装备表(装备ID,装备名,描述,价格)

        用户装备联系表(用户ID,装备ID,其它描述)

        订单装备联系表(订单ID,装备ID,其它描述)

        有时,可能会灵感一现:用户A可能拥有100个装备aa,用户装备联系表,得有100条重复数据啊!这不符合主键!

        所以,用户装备联系表加上属性“装备数量”。

        同理,订单装备联系表加上“装备数量”。

至此,初步的表设计完成。

范式规范化

        第一范式

                1NF要求:在业务层面,要求所有的列都不可分。

                显然满足。

        第二范式

                2NF要求:所有的列,直接或间接依赖主键。

                显然满足。

        第三范式

                3NF要求:所有的列,直接依赖于主键;并且,列与列之间无依赖关系。

                虽然这么说不好,但是确实也满足。

所以,这个数据库就设计完成了,我们拥有了一个可以使用的数据库!

 我是蚊子码农,如有补充或者疑问,欢迎在评论区留言。个人的知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/18906.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索数组处理:奇数的筛选与替换

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、数组中的奇数筛选 二、将奇数替换为负一 总结 一、数组中的奇数筛选 在处理数组数据时…

【Qt】初识

一、使用Label显示Hello World 1.ui设计 可以在Qt Designer中拖拽方式进行创建 2.代码方式 在myqwidget.cpp文件中添加下列代码 二、对象树 我们在堆上创建了QLabel类的对象。但是我们没有去delete,这样会产生内存泄漏吗? 答案是不会。label对象会在…

ChatGPT的基本原理是什么?又该如何提高其准确性?

在深入探索如何提升ChatGPT的准确性之前,让我们先来了解一下它的工作原理吧。ChatGPT是一种基于深度学习的自然语言生成模型,它通过预训练和微调两个关键步骤来学习和理解自然语言。 在预训练阶段,ChatGPT会接触到大规模的文本数据集&#x…

输入输出(1)——C++的输入输出概述

目录 一、C的输入输出 (一) C的输入输出 (二)C语言的scanf和printf 二、C的输入输出流 (一) iostream类库中有关的类 (二) iostream.h头文件的流对象和重载运算符 一、C的输入输出 (一) C的输入输出 之前用到的输入输出,都是以终端…

在做题中学习(62):矩阵区域和

1314. 矩阵区域和 - 力扣(LeetCode) 解法:二维前缀和 思路:读题画图才能理解意思:dun点点的是mat中的一个数,而要求的answer同位置的数 以点为中心上下左右延长 k 个单位所围成长方形的和。 因为最后answ…

IPV4地址介绍

4.1IP地址简介 目前的全球因特网所采用的协议族是TCP/IP协议族。IP是TCP/IP协议族中网络层的协议,是TCP/IP协议族的核心协议。IP协议定义了一种地址编码,称为IP地址,它是网络中网络段、网络设备接口、主机的编码,它并不是一种物理…

Linux离线一键安装Docker及docker-compose环境

背景: 在当前软件部署运维环境中由于Docker容器化优势越来越明显,因些被许多公司运维所采用,那首先如何快速安装Docker及docker-compose基础环境就第一时间被人们关注,本人同样在经过多次手工逐条用命令安装的过程,整理…

基于51单片机的温湿度控制系统

一.硬件方案 本设计采用51单片机每2秒钟从DHT11温湿度传感器中读入温度和湿度,在液晶屏上即时显示。液晶屏上同时显示温湿度上限值,该上限值保存外外部EEPROM存储器中,掉电不失,并且可以通过四只按键上调或下调。当温度或湿度值超…

[猫头虎分享21天微信小程序基础入门教程]第21天:小程序的社交分享与消息推送

[猫头虎分享21天微信小程序基础入门教程]第21天:小程序的社交分享与消息推送 第21天:小程序的社交分享与消息推送 📲 自我介绍 大家好,我是猫头虎,一名全栈软件工程师。今天我们继续微信小程序的学习,重…

MQ第②讲~保证消息可靠性

前言 上一讲我们讲了MQ实际工作中常见的应用场景,这一节讲一下消息的可靠性,如果对MQ掌握程度比较高的铁子,可以不用看,节省您宝贵的时间。 消息的大致链路 消息从投递到消费需要考虑如下几个问题 生产者的消息是否成功投递到消…

虚拟机改IP地址

使用场景:当你从另一台电脑复制一个VMware虚拟机过来,就是遇到一个问题,虚拟的IP地址不一样(比如,一个是192.168.1.3,另一个是192.168.2.4,由于‘1’和‘2’不同,不是同一网段&#…

浅谈路由器转发数据包

当路由器转发数据包时,它会经历一系列步骤,包括接收数据包、路由表查询、以及转发数据包。以下是详细的步骤描述: 1. 接收数据包 以太网帧到达端口:当一个以太网帧到达路由器的某个网络接口(端口)时&#…

20240529瑞芯微官方Toybrick TB-RK3588开发板的Debian11下使用SCP拷贝文件

20240529瑞芯微官方Toybrick TB-RK3588开发板的Debian11下使用SCP拷贝文件 2024/5/29 20:48 1、ADB链接异常。 2、BT打开之后找不到设备? 不清楚:是我拿到的开发板的问题,还是Toybrick/Rockchip官方没有做好。 3、现在最新版本的WINSCP&…

154.找出出现至少三次的最长特殊字符串|(力扣)

代码解决 class Solution { public:int maximumLength(string s) {// 使用unordered_map来存储每个连续子串出现的次数unordered_map<string, int> mp;string key; // 存储当前的连续子串int ans -1; // 存储最终的答案&#xff0c;如果没有符合条件的子串&#xff0c…

高级数据结构-并查集

例题1&#xff1a; Alice和Bob玩了一个古老的游戏&#xff1a;首先画一个 &#x1d45b;&#x1d45b; 的点阵&#xff08;下图 n3 &#xff09;。 接着&#xff0c;他们两个轮流在相邻的点之间画上红边和蓝边&#xff1a; 直到围成一个封闭的圈&#xff08;面积不必为 1&#…

如何更改SSH服务器端口以减少蛮力攻击

本周有一个客户&#xff0c;购买Hostease的独立服务器&#xff0c;询问我们的在线客服&#xff0c;如何更改SSH服务器端口以减少蛮力攻击&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对…

8086 汇编笔记(二):寄存器(内存访问)

一、内存中字的存储 字单元的概念&#xff1a;字单元&#xff0c;即存放一个字型数据(16 位)的内存单元&#xff0c;由两个地址连续的内存单元组成 由上一章学习可知&#xff1a;高地址内存单元中存放字型数据的高位字节&#xff0c;低地址内存单元中存放字型数据的低位字节 …

扎气球最高分-第13届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第74讲。 扎气球最高分&…

Spring框架温习

Spring Spring是一个全面的、企业应用开发一站式的解决方案&#xff0c;贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。 Spring 特点&#xff1a; 轻量级、控制反转、面向切面、容器、框架集合 Spring 核心组件&#xff1a; Spring 常用模块&…

【Redis】 关于 Redis 有序集合类型

文章目录 &#x1f343;前言&#x1f334;普通命令介绍&#x1f6a9;zadd&#x1f6a9;zcard&#x1f6a9;zcount&#x1f6a9;zrange&#x1f6a9;zrevrange&#x1f6a9;zrangebyscore&#x1f6a9;zpopmax&#x1f6a9;zpopmin&#x1f6a9;zrank&#x1f6a9;zrevrank&…