MySQL中外键的使用及外键约束策略
一、外键约束的概念
外键约束(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; -- 删除掉错误的数据
在没有外键约束的情况下,其实学生表(从表)中的班级号是可以任意插入的,造成了数据的不一致性
(二)更新和删除表数据
- 更新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
- 删除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, CONSTRAINTfk_stu_classcnoFOREIGN KEY (cno) REFERENCESt_class
(二) 更新和删除数据
更新和删除数据时,涉及到外键策略,我们先尝试着去改动和删除一些数据。
- 更新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, CONSTRAINTfk_stu_classcnoFOREIGN KEY (cno) REFERENCESt_class(cno))
时间: 0.002s
因为添加了外键约束,两个表已经建立了关系,为了维持数据的一致性,当改动班级表中的班级号时,原有的学生表中的编号也需要改动,默认情况下是不执行的,需要添加一些条件。
- 删除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, CONSTRAINTfk_stu_classcnoFOREIGN KEY (cno) REFERENCESt_class(cno))
时间: 0.008s
和更新时的报错原因一样,同样是因为外键的原因。
(三)外键策略
tips:cascade 操作 和 set null 操作 在表的创建添加外键约束时即可添加,我这里是为了方便直接修改外键约束策略了。灵活的根据业务将set null 和 cascade 结合起来使用
- 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);
- 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;
- 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),-- 当主表中的数据更新时,从表数据级联更新,当主表数据删除时,从表数据设置为Nullconstraint 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”
相关文章:
MySQL中外键的使用及外键约束策略
一、外键约束的概念 外键约束(FOREIGN KEY,缩写FK是数据库设计的一个概念,它确保在两个表之间的关系保持数据的一致性和完整性。 外键是指表中的某个字段的依赖于另一张表中某个字段的值,而被依赖的字段必须具有主键约束或者唯一约束&#…...
Home Assistant使用ios主题更换背景
Home Assistant使用ios主题、更换背景 lovelace-ios-dark-mode-theme 默认前置情况,1、已安转HACS插件2、搜索安装 IOS Dark Mode Theme1)第一、二步应该很容易实现,configuration.yaml文件很容易被找到2)而本人在进行第三步操作时…...
深入了解鼠标光标的设置过程
有一位读者问了这样一个问题: “为什么鼠标光标的设定绑定在窗口类,而不是窗口上?” 这个问题隐含地假设了光标与窗口类相关联。虽然每个窗口类都有一个关联的光标,但决定使用哪个光标的是窗口。 光标设置过程在 WM_SETCURSOR 消…...
数据结构-散列表
列表(Hash Table),又称哈希表,是一种数据结构,特点是:数据元素的关键字与其存储地址直接相关 例:有一堆数据元素,关键字分别为{19,14,23ÿ…...
一款IT团队都在用的私有化知识库,技术开放,还开源了!
IT和软件开发团队需要处理大量的技术文档和知识,通过建立内部知识库,可以将技术文档、代码示例、最佳实践等知识整理和归档起来,方便团队成员查找和参考。 IT和软件开发团队为什么要建立内部知识库? 提高知识管理效率:…...
解决 docker compose 官方 MySQL 镜像在容器中不能输入中文的问题
该问题可以通过添加环境变量解决,途径如下: 一、如果容器没条件或不允许重启,可通过命令行方式临时解决。 docker compose exec SERVICE-NAME env LANGC.UTF-8 mysql -u username -p 二、修改 docker-compose.yml 配置文件一劳永逸 envir…...
基于连续Hopfield神经网络优化——旅行商问题优化计算
大家好,我是带我去滑雪! 利用神经网络解决组合优化问题是神经网络应用的一个重要方面。所谓组合优化问题,就是在给定约束条件下,使目标函数极小(或极大)的变量组合问题。将Hopfield网络应用于求解组合优化问…...
SpringBoot整合Activiti7——定时器事件(九)
文章目录 定时器事件时间定义时间固定时间段时间周期 1.开始事件2.中间事件3.边界事件代码实现xml文件自定义服务任务监听器自定义用户任务监听器测试流程流程执行步骤 定时器事件 可以用在开始事件、中间事件、边界事件上,边界事件可以是中断和非中断边界事件 需要…...
轻量封装WebGPU渲染系统示例<29>- 深度模糊DepthBlur(源码)
实现方式: step1. 通过mrt机制,输出颜色和深度相关数据的两张rtt纹理。 step2. 基于上述颜色纹理,生成一张模糊之后的新rtt纹理。 setp3. 基于深度(也就是距离摄像机的远近)数据,合成颜色和模糊纹理数据,并最终输出。 当前示例…...
LeetCode226. Invert Binary Tree
文章目录 一、题目二、题解2.1 前序遍历版本2.2 中序遍历版本2.3 后序遍历版本 一、题目 Given the root of a binary tree, invert the tree, and return its root. Example 1: Input: root [4,2,7,1,3,6,9] Output: [4,7,2,9,6,3,1] Example 2: Input: root [2,1,3] Ou…...
Java设计模式-创建型模式-建造者模式
建造者模式 建造者模式案例与工厂模式的区别:Builder 注解 建造者模式 建造者模式是将一个复杂对象的构件与表示分离,使得同样的构件过程可以创建不同的表示。 建造者模式将内部构件的创建和组装分割开,一般使用链式编程,代码整洁…...
PyQt中QFrame窗口中的组件不显示的原因
文章目录 问题代码(例)原因和解决方法 问题代码(例) from PyQt5.QtWidgets import * from PyQt5.QtGui import QFont, QIcon, QCursor, QPixmap import sysclass FrameToplevel(QFrame):def __init__(self, parentNone):super().…...
git 命令行回退版本
git 命令行回退版本 git 命令行回退版本命令: 1.切换到需要回退的分支 git checkout branch-v2.0.02.更新远程分支 git fetch3.找到需要回退版本的版本号git revert a6914da55ff40a09e67ac2426b86f1212e6580eb4.清除工作区缓存git clean -df5.强制提交git push -f...
IntelliJ IDEA 安装 GitHub Copilot插件 (最新)
注意: GitHub Copilot 插件对IDEA最低版本要求是2021.2,建议直接用2023.3,一次到位反正后续要升级的。 各个版本的依赖关系,请参照: ##在线安装: 打开 IntelliJ IDEA扩展商店,输入 "Git…...
viewpage选择器
GitHub - hackware1993/MagicIndicator: A powerful, customizable and extensible ViewPager indicator framework. As the best alternative of ViewPagerIndicator, TabLayout and PagerSlidingTabStrip —— 强大、可定制、易扩展的 ViewPager 指示器框架。是ViewPagerIndi…...
vue中如何将json数组指定的key赋值给el-form-item并均匀的分成2列
在Vue中,你可以使用v-for指令来遍历JSON数组,并将指定的key赋值给el-form-item。下面是一个示例: <template><el-form><el-row><el-col :span"6" v-for"item in jsonArray" :key"item.key&qu…...
笔记本分屏怎么操作?3个方法提高工作效率!
“有朋友知道笔记本怎么才能实现分屏吗?我在工作时,经常需要来回切换屏幕,效率真的太低了,有什么方法可以实现两个屏幕同时使用吗?” 在现代生活中,多任务处理已成为常态,而笔记本分屏技术为用户…...
Android 使用poi生成Excel ,word并保存在指定路径内
一添加依赖(一定要用新版依赖防止一些bug) minSdk 26 //注意最小支持SDK26 dependencies {implementation org.apache.poi:poi:5.2.4implementation org.apache.poi:poi-ooxml:5.2.4implementation javax.xml.stream:stax-api:1.0-2 }二,创…...
嵌入式杂记 -- MCU的大小端模式
MCU的大小端模式 大端模式小端模式大小端模式测试联合体概念MCU大小端模式测试大端模式测试小端模式测试 大小端模式转换 在进行MCU开发的时候,我们需要注意MCU的数据存储模式,在嵌入式中有两种不同的存储模式,分别是 大端模式和小端模式。 …...
对这套BI零售数据分析方案心动,是零售人天性
零售数据分析做了这么多年,难道真的没累积点经验,摸索出一条又快又能满足绝大多数需求的数据分析捷径?别人不知道,奥威BI还真就有这么一套标准化的BI零售数据分析方案,不管是服装零售、医药连锁、商超都能利用这套方案…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
