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

文章目录
- 前言:
- [一. 表约束核心概念](#一. 表约束核心概念)
- [二. 基础约束:NULL/NOT NULL 与 DEFAULT](#二. 基础约束:NULL/NOT NULL 与 DEFAULT)
-
- [2.1 空属性约束(NULL/NOT NULL)](#2.1 空属性约束(NULL/NOT NULL))
- [2.2 默认值约束(DEFAULT)](#2.2 默认值约束(DEFAULT))
- [2.3 列描述(COMMENT)](#2.3 列描述(COMMENT))
- [2.4 零填充约束(ZEROFILL)](#2.4 零填充约束(ZEROFILL))
- [三. 核心约束:主键、自增长与唯一键](#三. 核心约束:主键、自增长与唯一键)
-
- [3.1 主键约束(PRIMARY KEY)](#3.1 主键约束(PRIMARY KEY))
- [3.2 自增长约束(AUTO_INCREMENT)](#3.2 自增长约束(AUTO_INCREMENT))
- [3.3 唯一键约束(UNIQUE KEY)](#3.3 唯一键约束(UNIQUE KEY))
- [四. 关联约束:外键(FOREIGN KEY)](#四. 关联约束:外键(FOREIGN KEY))
-
- [4.1 外键核心规则](#4.1 外键核心规则)
- [4.2 实战案例](#4.2 实战案例)
- [4.3 外键的意义](#4.3 外键的意义)
- [五. 综合实战:设计电商订单表](#五. 综合实战:设计电商订单表)
- [六. 约束选型避坑指南和总结](#六. 约束选型避坑指南和总结)
- 结尾:
前言:
在 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:字段不允许为空,插入 / 更新时必须赋值。
实战案例:
创建班级表,要求班级名和教室不能为空:
sql
-- 创建表(班级名和教室非空)
CREATE TABLE myclass(
class_name VARCHAR(20) NOT NULL,
class_room VARCHAR(10) NOT NULL
);
-- 插入合法数据(成功)
INSERT INTO myclass VALUES('class1', '301');
-- 插入非法数据(未给class_room赋值,报错)
INSERT INTO myclass(class_name) VALUES('class2');
-- 报错:ERROR 1364 (HY000): Field 'class_room' doesn't have a default value
2.2 默认值约束(DEFAULT)
当字段经常性出现某个固定值时,可设置DEFAULT,插入时省略该字段则自动使用默认值。
实战案例:
创建用户表,年龄默认 0,性别默认 "男":
sql
CREATE TABLE tt10(
name VARCHAR(20) NOT NULL, -- 非空(必须赋值)
age TINYINT UNSIGNED DEFAULT 0, -- 默认0
sex CHAR(2) DEFAULT '男' -- 默认男
);
-- 插入时仅赋值name,age和sex使用默认值
INSERT INTO tt10(name) VALUES('zhangsan');
-- 查询结果
SELECT * FROM tt10;
-- +----------+-----+-----+
-- | name | age | sex |
-- +----------+-----+-----+
-- | zhangsan | 0 | 男 |
-- +----------+-----+-----+
注意 :NOT NULL和DEFAULT一般不同时使用(DEFAULT已保证字段非空)。

2.3 列描述(COMMENT)
COMMENT用于描述字段含义,无实际校验作用,仅方便开发者和 DBA 理解表结构,需通过SHOW CREATE TABLE查看。
sql
CREATE TABLE tt12(
name VARCHAR(20) NOT NULL COMMENT '姓名',
age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄',
sex CHAR(2) DEFAULT '男' COMMENT '性别'
);
-- desc无法查看注释
DESC tt12;
-- 通过SHOW CREATE TABLE查看注释
SHOW CREATE TABLE tt12\G
-- 结果:
-- `name` varchar(20) NOT NULL COMMENT '姓名',
-- `age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',
-- `sex` char(2) DEFAULT '男' COMMENT '性别'
2.4 零填充约束(ZEROFILL)
仅对数字类型有效,当字段值的宽度小于设定宽度时,自动在左侧填充 0(仅格式化显示,实际存储值不变)。
实战案例:
sql
-- 创建表,a字段设置zerofill
CREATE TABLE tt3(
a INT(5) UNSIGNED ZEROFILL, -- 宽度5,零填充
b INT(10) UNSIGNED
);
-- 插入数据
INSERT INTO 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:单字段主键
sql
-- 创建表时指定主键
CREATE TABLE tt13(
id INT UNSIGNED PRIMARY KEY COMMENT '学号(主键)',
name VARCHAR(20) NOT NULL
);
-- 插入合法数据(成功)
INSERT INTO tt13 VALUES(1, 'aaa');
-- 插入重复主键(报错)
INSERT INTO tt13 VALUES(1, 'bbb');
-- 报错:ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
实战案例 2:复合主键(多字段联合主键)
当单个字段无法唯一标识记录时,可使用复合主键(多字段联合唯一):
sql
-- 学生成绩表:id(学号)+ course(课程代码)为复合主键
CREATE TABLE tt14(
id INT UNSIGNED,
course CHAR(10) COMMENT '课程代码',
score TINYINT UNSIGNED DEFAULT 60 COMMENT '成绩',
PRIMARY KEY(id, course) -- 复合主键
);
-- 插入合法数据(成功)
INSERT INTO tt14(id, course) VALUES(1, '123');
-- 插入重复复合主键(报错)
INSERT INTO tt14(id, course) VALUES(1, '123');
-- 报错:ERROR 1062 (23000): Duplicate entry '1-123' for key 'PRIMARY'
主键的添加与删除
sql
-- 给已有表添加主键
ALTER TABLE tt13 ADD PRIMARY KEY(id);
-- 删除主键(注意:若主键关联自增长,需先取消自增长)
ALTER TABLE tt13 DROP PRIMARY KEY;
3.2 自增长约束(AUTO_INCREMENT)
自增长字段会 自动从当前最大值 + 1 生成新值,核心特性:
- 必须是整数类型;
- 必须是索引(
KEY一栏有值,通常与主键搭配); - 一张表最多只能有一个自增长。
实战案例:
sql
-- 主键+自增长(逻辑主键)
CREATE TABLE tt21(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10) NOT NULL DEFAULT ''
);
-- 插入时省略id,自动递增
INSERT INTO tt21(name) VALUES('a');
INSERT INTO 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 个 | 多个 |
| 核心作用 | 标识唯一记录 | 保证业务字段不重复 |
实战案例 :
创建学生表,学号唯一(允许为空):
sql
CREATE TABLE student(
id CHAR(10) UNIQUE COMMENT '学号(唯一,可空)',
name VARCHAR(10)
);
-- 插入合法数据(成功)
INSERT INTO student(id, name) VALUES('01', 'aaa');
INSERT INTO student(id, name) VALUES(NULL, 'bbb'); -- 空值允许
-- 插入重复唯一键(报错)
INSERT INTO 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:
sql
-- 1. 创建主表(班级表)
CREATE TABLE myclass(
id INT PRIMARY KEY, -- 主键
name VARCHAR(30) NOT NULL COMMENT '班级名'
);
-- 2. 创建从表(学生表),添加外键
CREATE TABLE stu(
id INT PRIMARY KEY,
name VARCHAR(30) NOT NULL COMMENT '学生名',
class_id INT,
-- 外键:class_id关联myclass的id
FOREIGN KEY (class_id) REFERENCES myclass(id)
);
-- 3. 插入主表数据
INSERT INTO myclass VALUES(10, 'C++大牛班'), (20, 'Java大神班');
-- 4. 插入合法从表数据(class_id在主表存在)
INSERT INTO stu VALUES(100, '张三', 10), (101, '李四', 20);
-- 5. 插入非法从表数据(class_id=30在主表不存在,报错)
INSERT INTO stu VALUES(102, '王五', 30);
-- 报错:ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
-- 6. 插入class_id=NULL(未分配班级,成功)
INSERT INTO stu VALUES(102, '赵六', NULL);
4.3 外键的意义
外键的核心价值是 "让数据库自动校验数据关联性",避免出现逻辑冲突(如不存在的班级、不存在的用户订单)。若不设置外键,需在程序中手动校验,增加开发成本且易出错。

五. 综合实战:设计电商订单表
结合所有约束,设计电商系统的商品表、客户表、购买表,满足以下需求:
- 商品表:商品编号自增主键,名称非空,单价默认 0;
- 客户表:客户编号自增主键,姓名非空,邮箱唯一,性别枚举(男 / 女),身份证唯一;
- 购买表:订单号自增主键,关联客户编号和商品编号(外键),购买数量默认 0。
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS bit32mall DEFAULT CHARACTER SET utf8;
USE bit32mall;
-- 1. 商品表(主表)
CREATE TABLE IF NOT EXISTS goods(
goods_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '商品编号',
goods_name VARCHAR(32) NOT NULL COMMENT '商品名称',
unitprice FLOAT NOT NULL DEFAULT 0.1 COMMENT '单价(单位:分)',
category VARCHAR(12) COMMENT '商品分类', // 也可以用枚举
provider VARCHAR(64) NOT NULL COMMENT '供应商名称' // 也可以用枚举
);
-- 2. 客户表(主表)
CREATE TABLE IF NOT EXISTS customer(
customer_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '客户编号',
name VARCHAR(32) NOT NULL COMMENT '客户姓名',
address VARCHAR(256) COMMENT '客户地址',
email VARCHAR(64) UNIQUE KEY COMMENT '电子邮箱(唯一)',
sex ENUM('男','女') NOT NULL COMMENT '性别',
card_id CHAR(18) UNIQUE KEY COMMENT '身份证(唯一)'
);
-- 3. 购买表(从表,关联客户表和商品表)
CREATE TABLE IF NOT EXISTS purchase(
order_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '订单号',
customer_id INT COMMENT '客户编号',
goods_id INT COMMENT '商品编号',
nums INT DEFAULT 1 COMMENT '购买数量',
-- 外键关联
FOREIGN KEY (customer_id) REFERENCES customer(customer_id),
FOREIGN KEY (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):保证表间数据逻辑一致。
结尾:
html
🍓 我是草莓熊 Lotso!若这篇技术干货帮你打通了学习中的卡点:
👀 【关注】跟我一起深耕技术领域,从基础到进阶,见证每一次成长
❤️ 【点赞】让优质内容被更多人看见,让知识传递更有力量
⭐ 【收藏】把核心知识点、实战技巧存好,需要时直接查、随时用
💬 【评论】分享你的经验或疑问(比如曾踩过的技术坑?),一起交流避坑
🗳️ 【投票】用你的选择助力社区内容方向,告诉大家哪个技术点最该重点拆解
技术之路难免有困惑,但同行的人会让前进更有方向~愿我们都能在自己专注的领域里,一步步靠近心中的技术目标!
结语:合理组合约束能让数据库表结构更健壮,减少程序中的数据校验代码,同时提升数据可靠性。如果需要针对具体场景(如用户表、订单表)优化约束设计,欢迎在评论区留言交流!创作不易,觉得有帮助的话,欢迎点赞、收藏、关注三连~ 后续会持续更新 MySQL 索引、查询优化等进阶内容,带你从入门到精通数据库设计。
✨把这些内容吃透超牛的!放松下吧✨ ʕ˘ᴥ˘ʔ づきらど
