写一个简单的demo来理解数据库外键
- 准备工作
安装MySQL
确保已安装MySQL,并启动服务。可以通过命令行或工具(如MySQL Workbench)操作。
创建数据库
sql
复制
CREATE DATABASE school;
USE school;
- 创建父表和子表
步骤 1:创建父表(students)
sql
复制
-- 父表:学生表(主键为 student_id)
CREATE TABLE students (
student_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE
) ENGINE=InnoDB; -- 必须使用 InnoDB 引擎
步骤 2:创建子表(courses)并添加外键
sql
复制
-- 子表:课程表(外键关联学生表的 student_id)
CREATE TABLE courses (
course_id INT PRIMARY KEY AUTO_INCREMENT,
course_name VARCHAR(50) NOT NULL,
student_id INT, -- 外键字段
CONSTRAINT fk_student -- 外键约束名称
FOREIGN KEY (student_id)
REFERENCES students(student_id) -- 关联父表的主键
ON DELETE CASCADE -- 级联删除
ON UPDATE CASCADE -- 级联更新
) ENGINE=InnoDB;
关键点解释:
ON DELETE CASCADE:当父表(students)中的某条记录被删除时,子表(courses)中关联的记录会自动删除。
ON UPDATE CASCADE:当父表的主键(student_id)更新时,子表的外键字段同步更新。
- 插入数据并测试外键约束
步骤 1:向父表插入数据
sql
复制
INSERT INTO students (name, email)
VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com');
步骤 2:向子表插入合法数据(外键存在)
sql
复制
-- 合法操作:student_id=1 存在于 students 表
INSERT INTO courses (course_name, student_id)
VALUES ('Math', 1);
步骤 3:尝试插入非法数据(外键不存在)
sql
复制
-- 非法操作:student_id=3 不存在于 students 表
INSERT INTO courses (course_name, student_id)
VALUES ('Physics', 3);
结果:MySQL 会抛出错误:
Cannot add or update a child row: a foreign key constraint fails
- 测试级联操作
场景 1:删除父表数据
sql
复制
-- 删除 Alice(student_id=1)
DELETE FROM students WHERE student_id = 1;
– 查看 courses 表
SELECT * FROM courses;
结果:
所有 student_id=1 的课程记录会被自动删除(级联删除)。
场景 2:更新父表主键
sql
复制
-- 将 Bob(student_id=2)的 ID 更新为 100
UPDATE students SET student_id = 100 WHERE student_id = 2;
– 查看 courses 表
SELECT * FROM courses;
结果:
子表中 student_id=2 的记录会被自动更新为 student_id=100(级联更新)。
- 修改外键约束
添加新外键(如课程表关联教师表)
sql
复制
-- 先创建教师表(父表)
CREATE TABLE teachers (
teacher_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
) ENGINE=InnoDB;
-- 修改课程表,添加 teacher_id 外键
ALTER TABLE courses
ADD COLUMN teacher_id INT,
ADD CONSTRAINT fk_teacher
FOREIGN KEY (teacher_id)
REFERENCES teachers(teacher_id);
删除外键
sql
复制
ALTER TABLE courses DROP FOREIGN KEY fk_teacher;
- 常见问题与排查
问题 1:无法创建外键
可能原因:
父表的主键字段与外键字段类型或长度不匹配。
父表未使用 InnoDB 引擎。
父表中不存在外键引用的数据。
问题 2:级联操作未生效
检查点:
确认外键定义时指定了 ON DELETE CASCADE 或 ON UPDATE CASCADE。
确保操作的是父表的主键字段。
- 总结
通过这个示例,你学会了:
外键的创建与删除
级联操作的实际效果
外键约束的验证与错误处理
关键设计原则:
外键字段必须引用父表的唯一键(通常是主键)。
级联操作需谨慎使用,避免误删数据。
高频写入场景中,外键可能影响性能,需权衡利弊。
下一步练习
设计多对多关系
创建一个 student_course 中间表,关联学生和课程(需两个外键)。
测试 SET NULL 和 RESTRICT 约束
修改外键的 ON DELETE 行为,观察结果差异。
通过 ORM 操作外键
尝试在 Django 或 Flask-SQLAlchemy 中实现类似模型。