数据库入门到初级 · 第 14/22 篇。实验口径:MySQL 8.4、InnoDB、utf8mb4。案例:小型商城。
“一对一”和“一对多”不是画图时随便选的线条,而是业务允许出现的数量关系。同一个对象,在不同业务里可能具有不同关系。先问“一个 A 最多关联多少个 B,反过来呢”,再决定怎样存。
1. 一对一:用户与扩展资料
假设每名用户最多一份扩展资料,资料里存简介与个人网站:
CREATE TABLE user_profiles_demo (
user_id BIGINT UNSIGNED PRIMARY KEY,
bio VARCHAR(500) NULL,
website VARCHAR(200) NULL,
CONSTRAINT fk_profile_user_demo
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
user_id 同时是主键与外键,所以同一用户最多出现一次。也可以另设资料主键,再对 user_id 加 UNIQUE。只有外键而没有唯一限制,并不能阻止一个用户存在多份资料。
这个结构允许用户没有扩展资料,因此更准确地说是“用户对应零或一份资料”。它不会自动保证每个用户都有资料。是否拆表还要看访问频率、权限边界和可选字段数量,不必把所有一对一数据都强行拆开。

2. 一对多:外键放在多的一方
一个用户可以下多张订单,每张订单只属于一个用户,所以 orders 存 user_id。如果订单字段非空,再配外键,就表达“每张订单必须指向一名存在的用户”。
反过来,在用户表里放 order1_id、order2_id,会出现上限问题;放一个逗号分隔的订单列表,又会让外键、去重和查询变得困难。
通常,一对多关系的“多”并不意味着必须有至少一条记录。例如小陈没有订单仍是合法用户。要求用户必须下过单,是另一层业务限制。
3. 多对多:让中间表表达关联事实
以学生选课为例,一名学生选多门课,一门课也被多名学生选择。下面是独立演示表,需在当前练习库里执行一次:
CREATE TABLE students_demo (
id BIGINT UNSIGNED PRIMARY KEY,
name VARCHAR(50) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE courses_demo (
id BIGINT UNSIGNED PRIMARY KEY,
name VARCHAR(100) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE enrollments_demo (
student_id BIGINT UNSIGNED NOT NULL,
course_id BIGINT UNSIGNED NOT NULL,
enrolled_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students_demo(id),
FOREIGN KEY (course_id) REFERENCES courses_demo(id)
) ENGINE=InnoDB;
复合主键防止同一学生重复选同一门课程。中间表可以保存关联自己的属性,例如选课时间和成绩;这些属性既不只属于学生,也不只属于课程。
如果同一课程允许在不同学期重复选修,主键就需要包含学期或指向具体开课班次。这再次说明:约束应该来自真实业务,而不是从示例照抄。
4. 商城订单明细为什么也是中间表
一张订单有多个商品,一个商品出现在多张订单里,因此需要 order_items。但它比一个只有双方编号的桥接表更丰富,还保存数量和成交快照。
是否使用独立自增主键,并不改变它表达多对多关联的事实。关键是有没有用额外唯一约束防止业务上不允许的重复,以及是否明确了规格、定制配置等维度。
5. 删除规则需要单独设计
外键可以选择限制删除、级联删除,或在允许可空时设为空。不要为了省事给所有关系都加 ON DELETE CASCADE。删除某人的临时偏好与删除历史交易记录,后果完全不同。
本系列订单关系采用限制删除。真实系统常通过停用、匿名化和保留必要交易记录处理用户生命周期,具体方案要结合业务和适用要求。
练习与答案
练习:员工和部门属于哪种关系? 如果每名员工只属于一个部门,部门有多名员工,是一对多,员工表存部门编号。如果允许同时加入多个部门,就变成多对多,需要关联表。表结构必须跟随业务规则。
练习:给 orders.user_id 加唯一约束会怎样? 会限制每名用户最多一张订单,这与本系列商城需求冲突。
上一篇:第 13 篇 · 系列目录 · 下一篇:第 15 篇