MySQL中外键的使用及外键约束策略

news2024/11/19 9:19:09

一、外键约束的概念

外键约束(FOREIGN KEY,缩写FK是数据库设计的一个概念,它确保在两个表之间的关系保持数据的一致性和完整性。

外键是指表中的某个字段的依赖于另一张表中某个字段的值,而被依赖的字段必须具有主键约束或者唯一约束,被依赖的数据表称为主表(父表),设置外键约束的表称为子表或者从表。

比方说:现在有两张表,学生表和班级表,学生表中的班级号字段的值取决于班级表中班级号字段。
在这里插入图片描述

主表(父表):班级表-班级编号-主键
从表(子表):学生表-班级编号-外键

二、不使用外键约束会出现的问题

首先创建这两张表,学生表和班级表,然后不添加班级号的外键约束,并且插入一些初始化数据。

(一)创建表及初始化数据

-- 创建班级表
create table t_class(
	cno int(4) primary key auto_increment, -- 班级号自增主键
	cname varchar(12) not null -- 班级名称不为空值
);

-- 查看班级表
select * from t_class;

-- 插入班级信息
insert into t_class values (null,'java01班') ,(null,'python01班'),(null,'大数据01班');


-- 创建学生表(不含有外键约束的)
create table t_student(
	sno int(4) primary key auto_increment, -- 学号为主键自增
	sname varchar(5) not null , -- 姓名为非空约束
	age int(3) check (age >= 18 and age <= 55), -- 年龄为18-55之间 检查约束
	sex char(1) default '男' check (sex = '男' || sex = '女'), -- 性别默认为男,只能是男或者女
	cno int(4) 
);

-- 查看学生表
select * from t_student;

-- 插入学生信息  编号从1001开始
insert into t_student values (1001,'张三',21,'男',1); 
insert into t_student values (null,'李四',21,'男',1); 
insert into t_student values (null,'王五',21,'男',2);
insert into t_student values (null,'赵六',21,'男',3);
insert into t_student values (null,'崔七',21,'男',4); # 插入不存在的班级编号依旧成功
delete from t_student where cno = 4; -- 删除掉错误的数据

在没有外键约束的情况下,其实学生表(从表)中的班级号是可以任意插入的,造成了数据的不一致性

(二)更新和删除表数据

  1. 更新java01班的班级号为9,学生表中的数据并没有进行更新,数据再次不一致
-- 更新班级表数据
-- 将java01班的编号修改为9号
update t_class set cno = 9 where cname = 'java01班' and cno = 1;
select * from t_class; -- 班级表中成功修改
select * from t_student; -- 学生表中java01班的学生的班级编号并没有修改为9
  1. 删除java01班的班级信息,学生表中的java01班的学生信息依旧没有变化,数据不一致性
-- 删除表数据
-- 删除java01班的班级信息
delete from t_class where cno = 9 ;
select * from t_class;
select * from t_student;

(三)小结

在不使用外键约束的情况下,增删改均会影响数据的不一致性和完整性。

三、使用外键约束及外键策略

(一)创建表及初始化数据

-- 创建班级表
create table t_class(
	cno int(4) primary key auto_increment,
	cname varchar(12) not null
);

-- 查看班级表
select * from t_class;

-- 插入班级信息
insert into t_class values (null,'java01班') ,(null,'python01班'),(null,'大数据01班');

-- 创建学生表 外键约束只有表级约束
create table t_student(
	sno int(4) primary key auto_increment, -- 学号为主键自增
	sname varchar(5) not null , -- 姓名为非空约束
	age int(3) check (age >= 18 and age <= 55), -- 年龄为18-55之间 检查约束
	sex char(1) default '男' check (sex = '男' || sex = '女'), -- 性别默认为男,只能是男或者女
	cno int(4),
  constraint fk_stu_classcno	foreign key (cno) references t_class (cno) -- 添加外键约束
);

-- 查看学生表
select * from t_student;

-- 插入学生信息  1.(在没有外键约束的情况下,其实我们插入任何班级号都是可以的)
insert into t_student values (1001,'张三',21,'男',1); -- 这里第一个插入的id会影响后面的id,从1001开始
insert into t_student values (null,'李四',21,'男',1); 
insert into t_student values (null,'王五',21,'男',2);
insert into t_student values (null,'赵六',21,'男',3);
-- > 1452 - Cannot add or update a child row: a foreign key constraint fails (`mytestdb`.`t_student`, CONSTRAINT `fk_stu_classcno` FOREIGN KEY (`cno`) REFERENCES `t_class` 
insert into t_student values (null,'崔七',21,'男',4); # 插入不存在的班级编号报错

这里插入不存在的班级编号时,直接保存,因为外键约束帮我们做出了限制.

1452 - Cannot add or update a child row: a foreign key constraint fails (mytestdb.t_student, CONSTRAINT fk_stu_classcno FOREIGN KEY (cno) REFERENCES t_class

(二) 更新和删除数据

更新和删除数据时,涉及到外键策略,我们先尝试着去改动和删除一些数据。

  1. 更新java01班的班级号为9
update t_class set cno = 9 where cno = 1;

报错:update t_class set cno = 9 where cno = 1
1451 - Cannot delete or update a parent row: a foreign key constraint fails (mytestdb.t_student, CONSTRAINT fk_stu_classcno FOREIGN KEY (cno) REFERENCES t_class (cno))
时间: 0.002s

因为添加了外键约束,两个表已经建立了关系,为了维持数据的一致性,当改动班级表中的班级号时,原有的学生表中的编号也需要改动,默认情况下是不执行的,需要添加一些条件。

  1. 删除java01班的班级信息
delete from t_class where cno = 1;

报错:delete from t_class where cno = 1
1451 - Cannot delete or update a parent row: a foreign key constraint fails (mytestdb.t_student, CONSTRAINT fk_stu_classcno FOREIGN KEY (cno) REFERENCES t_class (cno))
时间: 0.008s
和更新时的报错原因一样,同样是因为外键的原因。

(三)外键策略

tips:cascade 操作 和 set null 操作 在表的创建添加外键约束时即可添加,我这里是为了方便直接修改外键约束策略了。灵活的根据业务将set null 和 cascade 结合起来使用

  1. no action 不允许操作–默认的外键策略 (修改从表的数据为Null,然后再修改主表的数据) 这种方法比较傻,就是硬写SQL
-- 修改java01班的班级编号为9
-- 1. 先修改学生表中java01班的数据为null
update t_student set cno = null where cno = 1;
-- 2. 更新班级表中的数据
update t_class set cno = 9 where cno = 1;
-- 3. 更新学生表中的数据
update t_student set cno = 9 where sno in (1001,1002);
  1. cascade 级联操作,操作主表的时候影响从表的外键信息 (先删除之前的外键约束再重新添加外键约束)。
-- 1.删除原有外键约束
alter table t_student drop foreign key fk_stu_classcno;
-- 2.添加新的外键约束策略  --- 在更新和删除时进行级联操作
alter table t_student add constraint fk_stu_classcno foreign key (cno) references t_class (cno) on update cascade on delete cascade;
-- 3. 更新数据 将java01班的班级号换为 19
update t_class set cno = 19 where cno = 9;
-- 4. 查询验证
select * from t_class;
select * from t_student;
  1. set null 置空操作,操作主表的时候影响从表的外键信息,从表对应的值为null值(先删除之前的外键约束然后重新添加新的外键约束)。
-- 1.删除原有外键约束
alter table t_student drop foreign key fk_stu_classcno;
-- 2.添加新的外键约束策略 --- 更新和删除时将从表的外键值都置为null
alter table t_student add constraint fk_stu_classcno foreign key (cno) references t_class (cno) on update set null  on delete set null;
-- 3. 更新数据 将java01班的班级号换为 29
update t_class set cno = 29 where cno = 19;
-- 4. 手动更新学生从表的数据
update t_student set cno = 29 where sno in (1001,1002);
-- 4. 查询验证
select * from t_class;
select * from t_student;

下面是一个在创建表时,添加外键约束策略的例子:

-- 创建班级表
create table t_class(
	cno int(4) primary key auto_increment,
	cname varchar(12) not null
);

-- 插入班级信息
insert into t_class values (null,'java01班') ,(null,'python01班'),(null,'大数据01班');

-- 查看班级表
select * from t_class;

-- 创建学生表 外键约束只有表级约束
create table t_student(
	sno int(4) primary key auto_increment, -- 学号为主键自增
	sname varchar(5) not null , -- 姓名为非空约束
	age int(3) check (age >= 18 and age <= 55), -- 年龄为18-55之间 检查约束
	sex char(1) default '男' check (sex = '男' || sex = '女'), -- 性别默认为男,只能是男或者女
	cno int(4),
	-- 当主表中的数据更新时,从表数据级联更新,当主表数据删除时,从表数据设置为Null
  constraint fk_stu_classcno	foreign key (cno) references t_class (cno) on update cascade on delete set null
);

-- 插入学生信息  1.(在没有外键约束的情况下,其实我们插入任何班级号都是可以的)
insert into t_student values (1001,'张三',21,'男',1); -- 这里第一个插入的id会影响后面的id,从1001开始
insert into t_student values (null,'李四',21,'男',1); 
insert into t_student values (null,'王五',21,'男',2);
insert into t_student values (null,'赵六',21,'男',3);

-- 查看学生表
select * from t_student;

-- 更新java01班班级编号为9
update t_class set cno = 9 where cno = 1;
select * from t_class;
select * from t_student;

-- 删除大数据01班
delete from t_class where cno = 3;
select * from t_class;
select * from t_student;

四、总结

当使用外键约束时,需要注意以下几点:

  • 外键约束只有表级约束,没有列级约束
  • 外键约束会影响表的性能,因为数据库必须对每个写操作执行额外的检查
  • 如果尝试插入不符合外键约束的行,数据库会抛出一个错误
  • 根据不同的业务需求自定义不同的外键策略 (cascade || set null)“constraint fk_stu_classcno foreign key (cno) references t_class (cno) on update cascade on delete set null”

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

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

相关文章

适用于初学者的 .NET MAUI

适用于初学者的 .NET MAUI | Microsoft Learn 记录微软Learn中用到的代码。文章比较粗糙&#xff0c;大部分是项目代码粘贴。想详细学习的可到上面的链接学习&#xff0c;代码可以从这里复制后直接运行。 练习中一共有两个页面&#xff1a; 1、MainPage.xaml 用于添加列表中的…

网络安全之认识托管威胁检测与响应(MDR)

随着数字化转型加速&#xff0c;企业的IT环境日益复杂&#xff0c;面临的网络安全威胁也在不断增加。传统的防御措施已经无法有效应对新型威胁&#xff0c;而且很多企业缺乏专业的网络安全团队和技术手段&#xff0c;导致大量的安全事件未能及时被发现和处理。 在这种背景下&a…

如何安装Node.js? 创建Vue脚手架

1.进入Node.js官网&#xff0c;点击LTS版本进行下载 Node.js (nodejs.org)https://nodejs.org/en 2.然后一直【Next】即可 3.打开【cmd】,输入【node -v】注意node和-v中间的空格 查看已安装的Node.js的版本号&#xff0c;如果可以看到版本号&#xff0c;则安装成功 创建Vue脚手…

Flutter实践一:package组织

1.架构概览 为了降低Flutter工程里lib的复杂度&#xff0c;应尽量拆分一些代码成为独立的package。如图&#xff1a; 我们将通用的组件、领域模型、API、features、存储、repository等抽取成了单独的package。这时lib只剩下多国语言、基本的页面、路由等代码了&#xff1a; 这…

Flutter笔记:使用Flutter构建响应式PC客户端/Web页面-案例

Flutter笔记 使用Flutter构建响应式PC客户端/Web页面-案例 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/detai…

Python基础入门例程53-NP53 前10个偶数(循环语句)

最近的博文&#xff1a; Python基础入门例程52-NP52 累加数与平均值(循环语句)-CSDN博客 Python基础入门例程51-NP51 列表的最大与最小(循环语句)-CSDN博客 Python基础入门例程50-NP50 程序员节&#xff08;循环语句&#xff09;-CSDN博客 目录 最近的博文&#xff1a; 描…

TCSVT(IEEE Transactions on Circuits and Systems for Video Technology)期刊投稿指南

目录 TCSVT 期刊简介 TCSVT 期刊影响因子和分区​ 期刊官方网站 期刊投稿网址 投稿指南网址 稿件格式要求 稿件提交指南 A. 提交稿件 B. 手稿格式 C. 摘要指南 D. 提交图形的指南 E. 页面和彩色图形费用 TCSVT 期刊简介 IEEE Transactions on Circuits and Systems…

RGB颜色空间与BMP格式图片

RGB颜色空间 RGB可以分为两大类&#xff1a;一种是索引形式&#xff0c;一种是像素形式&#xff1a; 索引形式&#xff1a;存储每个像素在调色板中的索引 RGB1&#xff1a;每个像素用1bit表示&#xff0c;调色板中只包含两种颜色&#xff08;黑白&#xff09;RGB4&#xff1a…

恒源云之oss上传数据、云台下载数据

目录 一、本地cmd上传数据二、使用云平台下载数据 一、本地cmd上传数据 需要下载恒源云客户端oss需要先将数据&#xff08;代码、数据集&#xff09;压缩成zip文件。 本地cmd打开oss&#xff0c;测试是否安成功 oss输入oss命令&#xff0c;并正确输入账号密码 oss login在个人…

按键编程 pal库和标准库

按钮的电路设计 电路的搭建 原理与编程 创建了两个变量 用来捕捉按键的状态 先让两个变量都为1 previous和current都为1 &#xff08;按键没按下&#xff09; 然后让current去捕捉按键的状态通过读gpioA的pin0 如果为0就是按键按下 如果为1就是按键没按下 然后赋值给current …

U-Boot 图形化配置及其原理

目录 U-Boot 图形化配置体验menuconfig 图形化配置原理make menuconfig 过程分析Kconfig 语法简介 添加自定义菜单 在前两章中我们知道uboot 可以通过mx6ull_alientek_emmc_defconfig 来配置&#xff0c;或者通过文件mx6ull_alientek_emmc.h 来配置uboot。还有另外一种配置uboo…

理解快速排序

理解快速排序 首先了解以下快速排序 快速排序&#xff08;QuickSort&#xff09;是一种常用的排序算法&#xff0c;属于比较排序算法的一种。它是由英国计算机科学家Tony Hoare于1960年提出的&#xff0c;是一种分而治之&#xff08;divide and conquer&#xff09;的算法。 …

systemd-timesyncd

介绍 systemd-timesyncd 是一个用于跨网络同步系统时钟的守护服务。它实现了一个 SNTP 客户端。与NTP的复杂实现相比&#xff0c;这个服务简单的多&#xff0c;它只专注于从远程服务器查询然后同步到本地时钟。除非你打算为客户端提供 NTP 服务器或者连接本地硬件时钟&#xff…

Keras实现图注意力模型GAT

简介&#xff1a;本文实现了一个GAT图注意力机制的网络层&#xff0c;可以在Keras中像调用Dense网络层、Input网络层一样直接搭积木进行网络组合。 一&#xff0c;基本展示 如下图所示&#xff0c;我们输入邻接矩阵和节点特征矩阵之后&#xff0c;可以直接调用myGraphAttention…

第90步 深度学习图像分割:U-Net建模

基于WIN10的64位系统演示 一、写在前面 从这一期开始&#xff0c;我们杀个回马枪&#xff0c;继续学习深度学习图像分割系列&#xff0c;以为4090上岗了。 图像分割是计算机视觉的一个重要任务&#xff0c;目的是将数字图像分割成多个部分或区域&#xff0c;这些部分通常对应…

大话IEC104 规约

2. iec104 协议的帧结构 iec104 基于TCP/IP 传输&#xff0c;是一个应用层协议&#xff0c; 其帧结构被称为 APDU&#xff0c;APDU 一般由 APCI 和 ASDU组成。 2.1 APDU (Application Protocol Data Unit) APDU 被称为应用协议数据单元&#xff0c;也就是一个iec104 的协议帧…

详解—搜索二叉树

一.二叉搜索树 1.1概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的…

Android修行手册 - 可变参数中星号什么作用(冷知识)

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

No183.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

【MySQL系列】 第一章 · MySQL概述

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…