MySQL 表约束核心指南:从基础约束到外键关联(含实战案例)

MySQL 表约束核心指南:从基础约束到外键关联(含实战案例)
在这里插入图片描述

🔥草莓熊Lotso:个人主页
❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》
✨生活是默默的坚持,毅力是永久的享受!


🎬 博主简介:

在这里插入图片描述

文章目录


前言:

在 MySQL 数据库设计中,数据类型定义了字段的存储格式,而表约束则从业务逻辑层面保证数据的合法性和完整性。没有约束的表可能出现空值、重复数据、逻辑冲突等问题(如学生所属班级不存在),而合理使用约束能让数据库 “自我校验”,减少程序中的数据校验逻辑。本文将全面拆解 MySQL 核心表约束,结合 PPT 实战案例讲解用法、区别与避坑点,帮你设计出健壮的数据库表结构。

一. 表约束核心概念

表约束是对表中字段的规则限制,用于保证数据的准确性、唯一性和关联性。MySQL 支持的核心约束包括:

  • 空属性约束(NULL/NOT NULL:限制字段是否允许为空;
  • 默认值约束(DEFAULT:字段未赋值时自动使用默认值;
  • 列描述(COMMENT:字段说明(无校验作用);
  • 零填充约束(ZEROFILL:数字类型不足指定宽度时填充 0;
  • 主键约束(PRIMARY KEY:唯一标识记录,非空且唯一;
  • 自增长约束(AUTO_INCREMENT:整数字段自动递增;
  • 唯一键约束(UNIQUE KEY:字段值唯一,允许为空;
  • 外键约束(FOREIGN KEY:关联两张表,保证数据逻辑一致性。
约束类型描述
空属性约束(NULL/NOT NULL)限制字段是否允许为空值。
默认值约束(DEFAULT)字段未赋值时自动使用默认值。
列描述(COMMENT)用于字段说明,没有校验作用。
零填充约束(ZEROFILL)数字类型不足指定宽度时在前面填充零。
主键约束(PRIMARY KEY)唯一标识表中的每一行记录,字段值非空且唯一。
自增长约束(AUTO_INCREMENT)整数字段在插入新记录时自动递增。
唯一键约束(UNIQUE KEY)保证字段值唯一,但允许为空值(通常只允许一个空值)。
外键约束(FOREIGN KEY)用于关联两张表,保证数据的一致性和完整性。

二. 基础约束:NULL/NOT NULL 与 DEFAULT

基础约束主要控制字段的空值和默认值,是表设计的基础要求。

2.1 空属性约束(NULL/NOT NULL)

  • NULL:默认值,字段允许为空(空值无法参与运算,如1+NULL=NULL);
  • NOT NULL:字段不允许为空,插入 / 更新时必须赋值。

实战案例:
创建班级表,要求班级名和教室不能为空:

-- 创建表(班级名和教室非空)CREATETABLE myclass( class_name VARCHAR(20)NOTNULL, class_room VARCHAR(10)NOTNULL);-- 插入合法数据(成功)INSERTINTO myclass VALUES('class1','301');-- 插入非法数据(未给class_room赋值,报错)INSERTINTO myclass(class_name)VALUES('class2');-- 报错:ERROR 1364 (HY000): Field 'class_room' doesn't have a default value

2.2 默认值约束(DEFAULT)

当字段经常性出现某个固定值时,可设置DEFAULT,插入时省略该字段则自动使用默认值。
实战案例:
创建用户表,年龄默认 0,性别默认 “男”:

CREATETABLE tt10( name VARCHAR(20)NOTNULL,-- 非空(必须赋值) age TINYINTUNSIGNEDDEFAULT0,-- 默认0 sex CHAR(2)DEFAULT'男'-- 默认男);-- 插入时仅赋值name,age和sex使用默认值INSERTINTO tt10(name)VALUES('zhangsan');-- 查询结果SELECT*FROM tt10;-- +----------+-----+-----+-- | name | age | sex |-- +----------+-----+-----+-- | zhangsan | 0 | 男 |-- +----------+-----+-----+

注意NOT NULLDEFAULT一般不同时使用(DEFAULT已保证字段非空)。

在这里插入图片描述

2.3 列描述(COMMENT)

COMMENT用于描述字段含义,无实际校验作用,仅方便开发者和 DBA 理解表结构,需通过SHOW CREATE TABLE查看。

CREATETABLE tt12( name VARCHAR(20)NOTNULLCOMMENT'姓名', age TINYINTUNSIGNEDDEFAULT0COMMENT'年龄', sex CHAR(2)DEFAULT'男'COMMENT'性别');-- desc无法查看注释DESC tt12;-- 通过SHOW CREATE TABLE查看注释SHOWCREATETABLE tt12\G -- 结果:-- `name` varchar(20) NOT NULL COMMENT '姓名',-- `age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',-- `sex` char(2) DEFAULT '男' COMMENT '性别'

2.4 零填充约束(ZEROFILL)

仅对数字类型有效,当字段值的宽度小于设定宽度时,自动在左侧填充 0(仅格式化显示,实际存储值不变)。
实战案例:

-- 创建表,a字段设置zerofillCREATETABLE tt3( a INT(5)UNSIGNED ZEROFILL,-- 宽度5,零填充 b INT(10)UNSIGNED);-- 插入数据INSERTINTO tt3 VALUES(1,2);-- 查询结果(a字段填充为00001)SELECT*FROM tt3;-- +-------+------+-- | a | b |-- +-------+------+-- | 00001 | 2 |-- +-------+------+-- 验证实际存储值(仍为1)SELECT a, HEX(a)FROM tt3;-- +-------+-------+-- | a | HEX(a) |-- +-------+-------+-- | 00001 | 1 |-- +-------+-------+
  • 关键:无ZEROFILL时,数字类型后的宽度(如INT(10))毫无意义,仅用于显示格式化。

三. 核心约束:主键、自增长与唯一键

主键、自增长、唯一键是保证数据唯一性的核心约束,解决 “重复数据” 和 “逻辑主键” 问题。

3.1 主键约束(PRIMARY KEY)

主键是表的 “唯一标识”,核心特性:

  • 非空(NOT NULL)且唯一(UNIQUE);
  • 一张表最多只能有一个主键;
  • 通常用于标识唯一记录(如用户 ID、学号)。

实战案例 1:单字段主键

-- 创建表时指定主键CREATETABLE tt13( id INTUNSIGNEDPRIMARYKEYCOMMENT'学号(主键)', name VARCHAR(20)NOTNULL);-- 插入合法数据(成功)INSERTINTO tt13 VALUES(1,'aaa');-- 插入重复主键(报错)INSERTINTO tt13 VALUES(1,'bbb');-- 报错:ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

实战案例 2:复合主键(多字段联合主键)
当单个字段无法唯一标识记录时,可使用复合主键(多字段联合唯一):

-- 学生成绩表:id(学号)+ course(课程代码)为复合主键CREATETABLE tt14( id INTUNSIGNED, course CHAR(10)COMMENT'课程代码', score TINYINTUNSIGNEDDEFAULT60COMMENT'成绩',PRIMARYKEY(id, course)-- 复合主键);-- 插入合法数据(成功)INSERTINTO tt14(id, course)VALUES(1,'123');-- 插入重复复合主键(报错)INSERTINTO tt14(id, course)VALUES(1,'123');-- 报错:ERROR 1062 (23000): Duplicate entry '1-123' for key 'PRIMARY'

主键的添加与删除

-- 给已有表添加主键ALTERTABLE tt13 ADDPRIMARYKEY(id);-- 删除主键(注意:若主键关联自增长,需先取消自增长)ALTERTABLE tt13 DROPPRIMARYKEY;

3.2 自增长约束(AUTO_INCREMENT)

自增长字段会 自动从当前最大值 + 1 生成新值,核心特性:

  • 必须是整数类型;
  • 必须是索引(KEY一栏有值,通常与主键搭配);
  • 一张表最多只能有一个自增长。

实战案例:

-- 主键+自增长(逻辑主键)CREATETABLE tt21( id INTUNSIGNEDPRIMARYKEYAUTO_INCREMENT, name VARCHAR(10)NOTNULLDEFAULT'');-- 插入时省略id,自动递增INSERTINTO tt21(name)VALUES('a');INSERTINTO tt21(name)VALUES('b');-- 查询结果SELECT*FROM tt21;-- +----+------+-- | id | name |-- +----+------+-- | 1 | a |-- | 2 | b |-- +----+------+-- 获取上次插入的自增长值SELECT LAST_INSERT_ID();-- 结果:1(批量插入返回第一个值)
在这里插入图片描述

3.3 唯一键约束(UNIQUE KEY)

唯一键用于保证字段值唯一,但允许为空(空值不参与唯一性比较),解决 “一张表多个唯一字段” 的需求(主键仅能有一个)。

  • 主键与唯一键的区别:
    以下是生成的表格:
特性主键(PRIMARY KEY)唯一键(UNIQUE KEY)
唯一性
非空性否(允许空值)
一张表数量最多 1 个多个
核心作用标识唯一记录保证业务字段不重复

实战案例
创建学生表,学号唯一(允许为空):

CREATETABLE student( id CHAR(10)UNIQUECOMMENT'学号(唯一,可空)', name VARCHAR(10));-- 插入合法数据(成功)INSERTINTO student(id, name)VALUES('01','aaa');INSERTINTO student(id, name)VALUES(NULL,'bbb');-- 空值允许-- 插入重复唯一键(报错)INSERTINTO student(id, name)VALUES('01','ccc');-- 报错:ERROR 1062 (23000): Duplicate entry '01' for key 'id'

四. 关联约束:外键(FOREIGN KEY)

外键用于定义主表和从表的关联关系,保证数据的逻辑一致性(如学生的班级必须存在于班级表中)。

4.1 外键核心规则

  • 外键定义在从表上,主表必须有主键或唯一键;
  • 从表外键字段的值必须在主表对应字段中存在,或为NULL;
  • 主表删除 / 修改关联记录时,需处理从表关联数据(如级联删除、拒绝操作)。
在这里插入图片描述

4.2 实战案例

创建班级表(主表)和学生表(从表),学生表的class_id关联班级表的id

-- 1. 创建主表(班级表)CREATETABLE myclass( id INTPRIMARYKEY,-- 主键 name VARCHAR(30)NOTNULLCOMMENT'班级名');-- 2. 创建从表(学生表),添加外键CREATETABLE stu( id INTPRIMARYKEY, name VARCHAR(30)NOTNULLCOMMENT'学生名', class_id INT,-- 外键:class_id关联myclass的idFOREIGNKEY(class_id)REFERENCES myclass(id));-- 3. 插入主表数据INSERTINTO myclass VALUES(10,'C++大牛班'),(20,'Java大神班');-- 4. 插入合法从表数据(class_id在主表存在)INSERTINTO stu VALUES(100,'张三',10),(101,'李四',20);-- 5. 插入非法从表数据(class_id=30在主表不存在,报错)INSERTINTO stu VALUES(102,'王五',30);-- 报错:ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails-- 6. 插入class_id=NULL(未分配班级,成功)INSERTINTO stu VALUES(102,'赵六',NULL);

4.3 外键的意义

外键的核心价值是 “让数据库自动校验数据关联性”,避免出现逻辑冲突(如不存在的班级、不存在的用户订单)。若不设置外键,需在程序中手动校验,增加开发成本且易出错。

在这里插入图片描述

五. 综合实战:设计电商订单表

结合所有约束,设计电商系统的商品表、客户表、购买表,满足以下需求:

  • 商品表:商品编号自增主键,名称非空,单价默认 0;
  • 客户表:客户编号自增主键,姓名非空,邮箱唯一,性别枚举(男 / 女),身份证唯一;
  • 购买表:订单号自增主键,关联客户编号和商品编号(外键),购买数量默认 0。
-- 创建数据库CREATEDATABASEIFNOTEXISTS bit32mall DEFAULTCHARACTERSET utf8;USE bit32mall;-- 1. 商品表(主表)CREATETABLEIFNOTEXISTS goods( goods_id INTPRIMARYKEYAUTO_INCREMENTCOMMENT'商品编号', goods_name VARCHAR(32)NOTNULLCOMMENT'商品名称', unitprice FLOATNOTNULLDEFAULT0.1COMMENT'单价(单位:分)', category VARCHAR(12)COMMENT'商品分类',// 也可以用枚举 provider VARCHAR(64)NOTNULLCOMMENT'供应商名称'// 也可以用枚举);-- 2. 客户表(主表)CREATETABLEIFNOTEXISTS customer( customer_id INTPRIMARYKEYAUTO_INCREMENTCOMMENT'客户编号', name VARCHAR(32)NOTNULLCOMMENT'客户姓名', address VARCHAR(256)COMMENT'客户地址', email VARCHAR(64)UNIQUEKEYCOMMENT'电子邮箱(唯一)', sex ENUM('男','女')NOTNULLCOMMENT'性别', card_id CHAR(18)UNIQUEKEYCOMMENT'身份证(唯一)');-- 3. 购买表(从表,关联客户表和商品表)CREATETABLEIFNOTEXISTS purchase( order_id INTPRIMARYKEYAUTO_INCREMENTCOMMENT'订单号', customer_id INTCOMMENT'客户编号', goods_id INTCOMMENT'商品编号', nums INTDEFAULT1COMMENT'购买数量',-- 外键关联FOREIGNKEY(customer_id)REFERENCES customer(customer_id),FOREIGNKEY(goods_id)REFERENCES goods(goods_id));

六. 约束选型避坑指南和总结

  • 优先使用非空约束:尽量让字段NOT NULL,空值会导致查询条件(如WHERE age=0)失效,且无法参与运算;
  • 主键选择逻辑 ID:主键建议用与业务无关的自增整数(如id),避免用身份证、手机号等业务字段(需频繁修改);
  • 唯一键保证业务唯一性:如邮箱、身份证等业务字段,用UNIQUE KEY约束,而非主键;
  • 外键谨慎使用:外键会降低表的插入 / 更新性能,高并发场景可去掉外键,在程序中校验关联性;
  • 自增长字段注意重置:删除表中数据后,自增长值不会自动重置,需用ALTER TABLE 表名 AUTO_INCREMENT=1手动重置。

总结:
MySQL 表约束是数据完整性的核心保障,从基础的空值 / 默认值约束,到核心的主键 / 唯一键约束,再到关联的外键约束,各自解决不同场景的问题:

  • 基础约束(NULL/DEFAULT/COMMENT/ZEROFILL):控制字段基础属性;
  • 核心约束(PRIMARY KEY/AUTO_INCREMENT/UNIQUE KEY):保证数据唯一性;
  • 关联约束(FOREIGN KEY):保证表间数据逻辑一致。

结尾:

🍓 我是草莓熊 Lotso!若这篇技术干货帮你打通了学习中的卡点: 👀 【关注】跟我一起深耕技术领域,从基础到进阶,见证每一次成长 ❤️ 【点赞】让优质内容被更多人看见,让知识传递更有力量 ⭐ 【收藏】把核心知识点、实战技巧存好,需要时直接查、随时用 💬 【评论】分享你的经验或疑问(比如曾踩过的技术坑?),一起交流避坑 🗳️ 【投票】用你的选择助力社区内容方向,告诉大家哪个技术点最该重点拆解 技术之路难免有困惑,但同行的人会让前进更有方向~愿我们都能在自己专注的领域里,一步步靠近心中的技术目标! 

结语:合理组合约束能让数据库表结构更健壮,减少程序中的数据校验代码,同时提升数据可靠性。如果需要针对具体场景(如用户表、订单表)优化约束设计,欢迎在评论区留言交流!创作不易,觉得有帮助的话,欢迎点赞、收藏、关注三连~ 后续会持续更新 MySQL 索引、查询优化等进阶内容,带你从入门到精通数据库设计。

✨把这些内容吃透超牛的!放松下吧✨ʕ˘ᴥ˘ʔづきらど

Read more

Flutter for OpenHarmony: Flutter 三方库 fixnum 解决鸿蒙 Web 与原生端 64 位大整数精度失真难题(精准计算护卫)

Flutter for OpenHarmony: Flutter 三方库 fixnum 解决鸿蒙 Web 与原生端 64 位大整数精度失真难题(精准计算护卫)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在进行 OpenHarmony 的跨平台开发时,你可能会遇到一个诡异的 Bug:同样的 64 位长整数(如 Int64),在鸿蒙原生(Native)模式下运行正常,但编译为 Flutter Web 模式在浏览器运行时,数值却发生了精度漂移或溢出。 1. 产生原因:JavaScript 原生的数字类型实质上是 64 位浮点数,它能安全表示的最大整数只有 53 位( 2 53 − 1 2^{53}-1 253−1)。 2. 后果:大额订单 ID、高精度的金融分位值、或是底层硬件的 64 位地址位,在

By Ne0inhk
Flutter for OpenHarmony:web_socket_channel 全平台 WebSocket 通信标准库,从原理到鸿蒙实战(3000字深度解析)

Flutter for OpenHarmony:web_socket_channel 全平台 WebSocket 通信标准库,从原理到鸿蒙实战(3000字深度解析)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在现代 App 开发中,实时通信(Real-time Communication)已成为标配。无论是社交聊天的由“推”变“拉”,还是股票行情的毫秒级跳动,亦或是智能家居的状态同步,传统的 HTTP 轮询(Polling)已无法满足低延迟、高并发的需求。 WebSocket 协议应运而生。它基于 TCP,但在握手阶段利用 HTTP 升级协议(Upgrade Header),成功后建立全双工(Full-Duplex)的长连接。在这条通道上,客户端和服务端可以随时互相推送数据,且头部开销极小。 在 Flutter 生态中,虽然 dart:io 提供了原生的 WebSocket 类,dart:

By Ne0inhk
【面试分享】前端 React 50个基础高频面试题,助你轻松拿 offer!

【面试分享】前端 React 50个基础高频面试题,助你轻松拿 offer!

目录 前端基础高频面试题之-- React 篇 1、什么是React? 2、React有什么特点? 3、列出React的一些主要优点。 4、React有哪些限制? 5、什么是JSX? 6、为什么浏览器无法读取JSX? 7、React中的组件是什么? 8、怎样解释 React 中 render() 的目的。 9、什么是 Props? 10、React中的状态是什么?它是如何使用的? 11、 React 中的箭头函数是什么?使用箭头函数的好处? 12、什么是高阶组件(HOC)? 13、你能用HOC做什么? 14、什么是纯组件? 16、什么是React 路由? 17、为什么 useState 返回的是数组而不是对象? 18、如何实现

By Ne0inhk
【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题 在开发 Web 应用时,尤其是集成了 Unity WebGL 内容的页面,遇到一个问题:当 Unity WebGL 渲染内容嵌入到一个 Tab 中时,切换 Tab 后画面会变黑,直到用户点击黑屏区域,才会恢复显示。 这个问题通常是因为 Unity 渲染在 Tab 切换时被暂停或未能获得焦点所致。 在本文中,我们将介绍如何在使用 Layui 框架时,通过监听 Tab 切换事件并强制 Unity WebGL 渲染恢复,来解决这一问题。 1. 问题描述 当 Unity WebGL 内容嵌入到页面中的多个

By Ne0inhk