本系列可作为数据库学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。
点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励!
系列文章目录
目录
目录
[3.1 定义(原文)](#3.1 定义(原文))
[3.2 反例(不满足 1NF)](#3.2 反例(不满足 1NF))
[3.3 正例(满足 1NF)](#3.3 正例(满足 1NF))
[4.1 前提](#4.1 前提)
[4.2 定义(原文)](#4.2 定义(原文))
[4.3 关键概念](#4.3 关键概念)
[4.4 反例(不满足 2NF)](#4.4 反例(不满足 2NF))
[4.5 不满足 2NF 会出现 4 大异常](#4.5 不满足 2NF 会出现 4 大异常)
[4.6 正例(满足 2NF)](#4.6 正例(满足 2NF))
[5.1 前提](#5.1 前提)
[5.2 定义(原文)](#5.2 定义(原文))
[5.3 反例(不满足 3NF)](#5.3 反例(不满足 3NF))
[5.4 正例(满足 3NF)](#5.4 正例(满足 3NF))
[九、E‑R 图(实体‑关系图)](#九、E‑R 图(实体‑关系图))
[9.1 什么是 E‑R 图](#9.1 什么是 E‑R 图)
[9.2 E‑R 图三要素](#9.2 E‑R 图三要素)
[9.3 三大关系(最重点)](#9.3 三大关系(最重点))
[十、实战建表 SQL(100% 可运行、无报错)](#十、实战建表 SQL(100% 可运行、无报错))
[10.1 一对一:用户 ↔ 账户](#10.1 一对一:用户 ↔ 账户)
[10.2 一对多:班级 ↔ 学生](#10.2 一对多:班级 ↔ 学生)
[10.3 多对多:学生 ↔ 课程 ↔ 成绩](#10.3 多对多:学生 ↔ 课程 ↔ 成绩)
前言
小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!
数据库设计是后端开发、数据建模、系统设计的核心基础。设计不好会导致:数据冗余大、更新异常、插入异常、删除异常、查询复杂、性能低下等一系列问题。
本篇文章内容包括:
- 数据库范式(1NF/2NF/3NF)定义 + 反例 + 正例 + 异常分析
- 数据库标准设计流程
- 类、实体、表三者对应关系
- E‑R 图三要素与三大关系(1:1 / 1:N / M:N)
- 一对一、一对多、多对多完整建表 SQL
- 所有原文案例、图表、说明全覆盖
一、本节学习目标
- 了解数据库范式
- 了解实例之间的关系
- 了解数据库的设计过程
- 了解类、实体、表之间的关系
二、什么是数据库范式
范式(Normal Form) :关系数据库设计时必须遵守的规范规则集合。目的:减少数据冗余、避免数据异常、保证数据一致性与完整性。
关系型数据库一共 6 种范式:
- 第一范式(1NF)
- 第二范式(2NF)
- 第三范式(3NF)
- 巴斯‑科德范式(BCNF)
- 第四范式(4NF)
- 第五范式(5NF,完美范式)
核心结论:
- 范式等级越高 → 数据冗余越小
- 范式越高 → 表越多、关联越多、IO 越频繁
- 实际开发满足 3NF 就足够!
三、第一范式(1NF)
3.1 定义(原文)
- 数据库表的每一列都是不可分割的原子数据项
- 不能是集合、数组、对象等非原子数据
- 满足 1NF 是关系数据库最基本要求
- 不满足 1NF 不能称为关系数据库
一句话:列不可再分!
3.2 反例(不满足 1NF)
设计学生表,需要记录学生信息 + 学校信息。
正取做法:学号、姓名、年龄、班级名、学校名、学校地址、学校电话
虽然这样不符合数据库设计规范,但是每一列都是不可再分的,最起码可以表明一个学生和一个班级以及学校之间的关系。
错误做法:学号、姓名、年龄、班级名、学校
把 "学校" 当作一列,而学校本身还能拆分为:
- 学校名
- 学校地址
- 学校电话
因为 "学校" 可拆分 → 违反原子性 → 不满足 1NF 。(而且并没有一个数据类型可以表示学校)
3.3 正例(满足 1NF)
把学校信息拆成独立列:
- 学生姓名
- 学校名称
- 学校地址
- 学校电话
每一列都不可再分 → 满足 1NF。
重要结论:在 MySQL 中,只要使用基本数据类型(int/varchar/date 等) ,天然满足 1NF。
四、第二范式(2NF)
4.1 前提
必须先满足 1NF。
4.2 定义(原文)
在满足 1NF 基础上:不存在非关键字段(非主键字段)对任意候选键(可以理解为主键、外键、没有主键时的唯一键)的部分函数依赖。(存在于复合主键(一个表中不能存在两个主键,但是一个主键可以包含多个列)的情况下)
通俗解释:
- 表中每一个非主键列,必须完全依赖整个主键
- 不能只依赖主键的一部分
- 常见于复合主键场景
4.3 关键概念
- 候选键:能唯一标识一行的列 / 列组合
- 主键:从候选键中选出一个作为主键
- 部分函数依赖:只依赖复合主键的一部分
4.4 反例(不满足 2NF)
需求:学生选课、课程有学分、学生有成绩。
学号、学生姓名、年龄、性别、课程名、学分、成绩
设计成一张大表:
| 学号 | 学生姓名 | 年龄 | 性别 | 课程名 | 学分 | 成绩 |
|---|---|---|---|---|---|---|
| 10001 | 张三 | 18 | 男 | MySQL | 50 | 98 |
| 10002 | 李四 | 19 | 女 | MySQL | 50 | 100 |
| 10003 | 王五 | 18 | 男 | MySQL | 50 | 89 |
| 10001 | 张三 | 18 | 男 | Java | 60 | 100 |
主键:学号 + 课程名(复合主键)
这个表中可以用学生和课程做复合主键在确认同学当前选修课的成绩(主要作用)
学生姓名、年龄和课程没有关系,即学生的姓名、年龄只依赖于学号,不依赖于课程,学分于学生没有关系,即学分只依赖于课程,不依赖于学生。
对于由两个或多个关键字段决定一条记录的情况,如果一行数据中有些字段只与关键字段中的一个有关系,那么这种就说他只存在部分函数依赖。
如果有这样的情况就说明这个表不满足第二范式。
问题:
- 姓名、年龄、性别 → 只依赖 学号
- 学分 → 只依赖 课程名
- 都没有依赖整个主键 → 部分依赖 → 不满足 2NF
4.5 不满足 2NF 会出现 4 大异常
-
数据冗余姓名、年龄、学分大量重复,浪费存储空间。
-
更新异常要改 MySQL 学分,必须更新所有 MySQL 行。中途失败会导致同一课程学分不一致。
-
插入异常新课还没有学生选 → 无法插入课程信息。
-
删除异常删除毕业学生成绩 → 课程与学分信息也被删掉。
4.6 正例(满足 2NF)
拆成 3 张表:
- 学生表(学号、姓名、年龄、性别)
- 课程表(课程 ID、课程名、学分)
- 成绩表(学生 ID、课程 ID、成绩)
每张表都是单主键,无部分依赖 → 满足 2NF。
重要结论:单主键的表,天然满足 2NF!
五、第三范式(3NF)
5.1 前提
必须先满足 2NF。
5.2 定义(原文)
在满足 2NF 基础上:不存在非关键字段对任一候选键的传递依赖。
通俗解释:
- 非主键列 只能依赖主键
- 不能依赖其他非主键列
- 禁止:主键 → A → B 这种传递链
5.3 反例(不满足 3NF)
学生表包含学院、学院电话:
| ID | 学号 | 姓名 | 学院 | 学院电话 |
|---|---|---|---|---|
| 1 | 10001 | 张三 | 计算机学院 | 88888888 |
| 2 | 10002 | 李四 | 网络安全学院 | 66666666 |
问题:
- 学院电话 依赖学院
- 学院 依赖学生 ID
- 形成传递依赖:学生 ID → 学院 → 学院电话 → 不满足 3NF
这两种强相关关系存在传递关系,通过学号找到所在学院,再找到学院电话,学院地址。所以是存本质上是存在两个实体的。
5.4 正例(满足 3NF)
拆成两张表:
- 学院表 (学院 ID、学院名、学院电话、地址)
- 学生表 (学生 ID、姓名、学院 ID)
学生表通过 学院 ID(外键) 关联学院表。无传递依赖 → 满足 3NF。
两张表都依赖于自己表中的主键,学生表可以通过外键与学院之间建立关联关系。
第三范式可以解决数据冗余,更新异常,插入异常,删除异常的问题。
六、三大范式最强总结(面试必背)
| 范式 | 核心 | 一句话记忆 |
|---|---|---|
| 1NF | 原子性 | 列不可再分 |
| 2NF | 完全依赖 | 非主键列依赖整个主键 |
| 3NF | 消除传递 | 非主键列只依赖主键 |
口诀:1NF 不可分,2NF 全依赖,3NF 不传递。
七、数据库设计
表的设计方法:
1.从需求中获得类,类对应到数据库中的实体,实体在数据库中就表现为一张一张的表,类中的属性就对应着表中的字段(列)。
2.确定类与类之间的关系。**(实体中的关系:**一对一关系,一对多关系,多对多关系,没有关系)
3.使用SQL创建具体的表
数据库设计标准流程:
- 从现实业务抽象出概念类类 = 现实世界抽象
- 确定实体与属性类 → 实体 → 数据库表属性 → 表的列
- 确定实体之间关系一对一、一对多、多对多
- 绘制 E‑R 图方便团队沟通、理解结构
- 根据 E‑R 图编写 SQL,创建数据库与表加主键、外键、约束
八、类、实体、表的关系(必考)
- 类(Java Class) → 业务抽象
- 实体(Entity) → 数据库概念(E‑R 图矩形)
- 表(Table) → MySQL 存储结构
对应关系:
- 类 → 实体 → 表
- 类的属性 → 实体属性 → 表的列
- 类的实例 → 实体实例 → 表的行
九、E‑R 图(实体‑关系图)
9.1 什么是 E‑R 图
Entity‑Relationship Diagram,用于数据库概念设计,可视化表达:实体、属性、关系。
9.2 E‑R 图三要素
- 实体:矩形(学生、课程、班级)
- 属性:椭圆形(姓名、年龄、学分)
- 关系:菱形(关联、选修、属于)
9.3 三大关系(最重点)
(1)一对一关系(1:1)
一个用户 ↔ 一个账户一个人 ↔ 一个身份证
设计: 在任意一张表加关联字段指向另一张表主键。
(2)一对多关系(1:N)
一个班级 → 多个学生一个部门 → 多个员工
设计: 在多的一方 加外键,指向一的一方主键。
**创建表:**分别为不同的实体创建表
学生表,班级表,创建表之后建立表与表之间的关联关系。
通过记录学生记录中的class_id可以表示学生在哪个班级。
student(student_id,name,age**,class_id);**
class(class_id,name);
(3)多对多关系(M:N)
学生 ↔ 课程商品 ↔ 标签用户 ↔ 角色
设计: 必须创建中间表,存储双方主键 + 关系属性。
十、实战建表 SQL(100% 可运行、无报错)
10.1 一对一:用户 ↔ 账户
sql
-- 用户表
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
nickname VARCHAR(20),
phone_num VARCHAR(11),
email VARCHAR(50),
gender TINYINT(1)
);
-- 账户表
DROP TABLE IF EXISTS account;
CREATE TABLE account (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
password VARCHAR(32) NOT NULL,
users_id BIGINT
);
10.2 一对多:班级 ↔ 学生
sql
-- 一的一方:班级表
DROP TABLE IF EXISTS class;
CREATE TABLE class (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
);
-- 多的一方:学生表(加外键)
DROP TABLE IF EXISTS student;
CREATE TABLE student (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
sno VARCHAR(10) NOT NULL,
age INT DEFAULT 18,
gender TINYINT(1),
enroll_date DATE,
class_id BIGINT,
FOREIGN KEY (class_id) REFERENCES class(id)
);
10.3 多对多:学生 ↔ 课程 ↔ 成绩
sql
-- 学生表
DROP TABLE IF EXISTS student;
CREATE TABLE student (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
sno VARCHAR(10) NOT NULL,
age INT DEFAULT 18,
gender TINYINT(1),
enroll_date DATE
);
-- 课程表
DROP TABLE IF EXISTS course;
CREATE TABLE course (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL
);
-- 中间表:成绩表
DROP TABLE IF EXISTS score;
CREATE TABLE score (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
score FLOAT,
student_id BIGINT,
course_id BIGINT,
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
);
十一、全文终极总结
- 1NF:列必须原子,不可再分
- 2NF:消除部分依赖,单主键天然满足
- 3NF:消除传递依赖,非主键只依赖主键
- 一对一:任意表加关联字段
- 一对多:多的一方加外键
- 多对多:必须用中间表
- 设计流程:抽象类 → 实体 → E‑R 图 → 建表
- 类 → 实体 → 表 一一对应
数据库设计的目标:低冗余、无异常、易扩展、高性能、好维护。

总结
以上就是今天要讲的内容,本文简单记录了数据库学习内容,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!