上一篇文章学到了数据类型,而数据类型只能限制数据的类型和长度 ,约束能从业务规则 层面保证数据合法、正确(比如邮箱唯一、姓名不能为空),是数据库表设计的核心规范。接下来我们来学习一下MySQL表的约束。我们重点学习 8 个高频约束:NULL / NOT NULL、DEFAULT、COMMENT、ZEROFILL、PRIMARY KEY、AUTO_INCREMENT、UNIQUE KEY、FOREIGN KEY。
再上一个文章我们还能知道如果我们向MySQL特定类型中插入不合法的数据,MySQL一般都是直接拦截我们的,不让我们做对应的操作!反过来,如果我们已经有数据成功被插入到MySQL中,那一定是插入时候合法的!所以,MySQL中,一般而言,数据类型本身也是一种约束------而这个约束是倒逼程序员,让程序员尽可能进行正确的插入。约束即约束使用者的!另外,如果你不是一个很好的使用者,MySQL也能保证数据插入合法。故保证数据库中的数据是可预期的,完整的。
目录
[1. 空属性约束:NULL / NOT NULL](#1. 空属性约束:NULL / NOT NULL)
[2. 默认值约束:DEFAULT](#2. 默认值约束:DEFAULT)
[3. 列描述:COMMENT](#3. 列描述:COMMENT)
[4. 零填充:ZEROFILL](#4. 零填充:ZEROFILL)
[5. 主键(PRIMARY KEY)](#5. 主键(PRIMARY KEY))
[6. 自增长(AUTO_INCREMENT)](#6. 自增长(AUTO_INCREMENT))
[7. 唯一键(UNIQUE KEY)](#7. 唯一键(UNIQUE KEY))
[8. 外键(FOREIGN KEY)](#8. 外键(FOREIGN KEY))
[MySQL 表约束全章总结](#MySQL 表约束全章总结)
1. 空属性约束:NULL / NOT NULL
字段默认允许为 NULL,但 NULL 不参与任何运算(任何值 + NULL 都为 NULL),实际开发中核心业务字段应尽量设置为 NOT NULL。
NULL:允许为空(默认)NOT NULL:不允许为空,插入时必须提供值
示例演示
-- NULL 无法参与运算
SELECT NULL;
SELECT 1 + NULL;
运行结果:

建表示例
创建班级表,要求班级名、教室都不能为空:
mysql> create table if not exists myclass(
-> name varchar(20) not null,
-> room varchar(10) not null);
查看:
desc myclass;
结果:

插入时若缺少必填字段,直接报错:
mysql> insert into myclass(name) values('class1');
ERROR 1364 (HY000): Field 'room' doesn't have a default value
所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这 就是"约束"。
2. 默认值约束:DEFAULT
当插入数据不指定某字段值时,自动使用预设的默认值,简化插入语句并保证数据完整性。只有设置了 DEFAULT 的列,插入时才能省略该列。但是用户如果插入了具体的数据,就用用户的,没有才默认的。
建表示
mysql> create table if not exists t10 (
-> name VARCHAR(20) NOT NULL,
-> age TINYINT UNSIGNED DEFAULT 0,
-> sex CHAR(2) DEFAULT '男'
-> );
查看:
desc t10;
结果:

插入时只给姓名,其他字段自动使用默认值:
mysql> insert into t10(name) values('张三');
Query OK, 1 row affected (0.00 sec)
查看:

注意:DEFAULT 与 NOT NULL 并不冲突,二者反而是互相补充、配合使用的关系。
设置 NOT NULL 用于强制字段必须有值、不能为空;搭配 DEFAULT 则可以在插入时不手动传值,自动使用默认值填充,既满足非空约束,又简化数据插入。
3. 列描述:COMMENT
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA 来进行了解。
- 作用 :给字段加注释说明,方便程序员 / 运维理解字段含义
- 规则 :
DESC 表名看不到注释,必须用SHOW CREATE TABLE查看
完整案例:创建用户表(年龄默认 0、性别默认男)
create table if not exists user_info(
name VARCHAR(20) NOT NULL COMMENT '用户名',
age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄,默认0岁',
sex CHAR(2) DEFAULT '男' COMMENT '性别,默认男'
);
查看创建结构:
show create table user_info\G
运行结果:

插入:
-- 插入数据:只填用户名,年龄、性别用默认值
insert into user_info(name) VALUES('张三');
查询:

4. 零填充:ZEROFILL
作用 :数字类型格式化显示 ,不足指定宽度时前面补0
关键 :只改变显示效果,不改变数据库实际存储的值
完整案例:数字补 0 展示
创建表,id字段设置:宽度5 + 零填充
mysql> create table if not exists num_test(
-> id int(5) unsigned zerofill comment '零填充测试');
插入:
-- 插入值1
insert into num_test values(1);
查询数据:显示00001
mysql> insert into num_test values(1);

验证真实存储值:还是1
mysql> select id, hex(id) from num_test;
结果:

5. 主键(PRIMARY KEY)
主键用于唯一标识表中的每一行记录 ,从根本上保证数据不重复、可精准定位。主键的核心约束:字段值不能重复,且不能为空。
特别注意:一张表最多只能有一个主键 ,但这不意味着主键只能设置在一列上 。主键可以只作用于单个字段 ,也可以同时作用于多个字段 ,由多个字段共同组成的主键称为复合主键。
主键基本特性
- 唯一性:主键字段(或字段组合)的值不能重复
- 非空性:主键字段自动隐含
NOT NULL约束,不允许为 NULL - 唯一性限制:一张表只能定义一个主键
- 类型建议:主键字段通常使用整数类型(INT、BIGINT),查询与存储效率更高
案例 1:创建表时直接指定单列主键
在字段定义后直接加上 primary key,该字段单独作为主键。
mysql> create table if not exists t13(
-> id int unsigned primary key comment '学号,主键非空且唯一',
-> name varchar(20) not null
-> );
查看:
desc t13;

Key 列显示 PRI,表示该字段是主键。
主键唯一性约束测试
mysql> insert into t13 values(1, 'aaa');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t13 values(1, 'abc');
ERROR 1062 (23000): Duplicate entry '1' for key 't13.PRIMARY'
主键值重复,插入失败。
追加 / 删除主键
表创建
mysql> create table if not exists t9(
-> id int unsigned,
-> name varchar(20) not null
-> );
查看:

没有主键。
追加主键 语法:
alter table 表名 add primary key(字段列表);
运行结果:

删除主键语法:
alter table 表名 drop primary key;
运行结果:

案例 2:复合主键(多列共同组成一个主键)
一张表只有一个主键,但这个主键可以由多个字段联合构成,只有这几个字段的组合完全重复时,才算主键冲突。
创建表( id 和 course 共同组成一个主键)
mysql> create table if not exists t14(
-> id int unsigned,
-> course char(10) comment '课程代码',
-> score tinyint unsigned default 60 comment '成绩',
-> primary key(id, course)
-> );
Query OK, 0 rows affected (0.01 sec)
查看:

复合主键约束测试
mysql> insert into t14 (id,course) values(1, '123');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t14 (id,course) values(1, '124');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t14 (id,course) values(2, '124');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t14 (id,course) values(1, '123');
ERROR 1062 (23000): Duplicate entry '1-123' for key 't14.PRIMARY'
有现象可知------只有id 和 course 同时重复,才会触发主键冲突。
6. 自增长(AUTO_INCREMENT)
auto_increment 表示:插入数据时不给该字段赋值,系统会自动取当前字段最大值 +1,生成一个新的唯一值。通常与主键搭配使用,作为自动生成的逻辑主键。
自增长特点
- 自增长字段必须是索引列(Key 列有值,如主键、唯一键)
- 自增长字段必须是整数类型
- 一张表最多只能有一个自增长字段
案例
创建表:
mysql> create table if not exists t15(
-> id int unsigned primary key auto_increment,
-> name varchar(10) not null default ''
-> );
插入:
mysql> insert into t15(name) values('张三');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t15(name) values('李四');
Query OK, 1 row affected (0.00 sec)
查看:

发现他自己增加了。
获取上一次插入的自增 ID
mysql> select last_insert_id();
运行结果:

批量插入时,返回的是批量中第一条记录的自增 ID。
索引简介
在关系数据库中,索引是一种独立的、物理性的排序存储结构,用于加快数据查找。可以把索引理解为图书的目录:通过目录可以快速定位页码,而不用一页页翻阅全书。
索引会对指定一列或多列的值进行排序,并存储指向真实数据行的指针。数据库在查询时,可以通过索引直接定位数据,避免全表扫描,从而大幅提升查询效率。主键、唯一键、自增长字段默认都会自动创建索引。
7. 唯一键(UNIQUE KEY)
在数据表设计中,除了主键需要具备唯一性外,业务上往往还存在其他字段也必须保证不重复,例如学号、工号、手机号、邮箱等。但一张表只能有一个主键,无法满足多字段同时唯一的约束需求,唯一键(UNIQUE KEY) 就是用来解决这个问题的。
唯一键用于保证字段取值在业务层面不重复,其规则与主键相似,但有一个关键不同:唯一键允许字段值为 NULL,并且可以存在多个 NULL,因为 NULL 不参与唯一性比较。
主键与唯一键的核心区别
- 主键:用于唯一标识一行记录,自带非空约束,一张表只能有一个,通常与业务无关,用于定位数据。
- 唯一键:用于保证业务字段不重复,允许为空,一张表可以有多个,专门约束业务逻辑上不能重复的数据。
设计原则建议实际开发中,建议主键使用与业务无关的自增 ID,而把身份证号、工号、学号这类业务唯一字段设为唯一键。这样即使未来业务规则变更,也不会影响主键结构,表结构更稳定。
案例演示
创建表(学号设为唯一键)
mysql> create table if not exists student(
-> id char(10) unique comment '学号,业务唯一,允许为空',
-> name varchar(10) not null
-> );
插入:
-- 正常插入
mysql> insert into student(id, name) values('1', '张三');
Query OK, 1 row affected (0.00 sec)
-- 插入重复学号,违反唯一约束,失败
mysql> insert into student(id, name) values('1', '李四');
ERROR 1062 (23000): Duplicate entry '1' for key 'student.id'
-- 插入 NULL,唯一键允许为空,成功
mysql> insert into student(id, name) values('null', '李四');
Query OK, 1 row affected (0.00 sec)
查看:

8. 外键(FOREIGN KEY)
外键是用于建立两张表之间关联关系、保证数据参照完整性的约束。它可以避免出现 "学生属于一个不存在的班级""商品对应一个不存在的分类" 这类逻辑非法的数据。
外键核心规则
- 外键约束建立在 ** 从表(子表)** 上
- 被引用的主表(父表)字段必须是主键或唯一键
- 从表外键列的值,必须在主表中存在,或者为 NULL
- 主表记录被从表引用时,不能随意删除或修改,避免数据断裂
外键语法
foreign key (从表字段) references 主表(主表关联字段)
案例实现

先创建主表:班级表
create table if not exists myclass (
id int primary key comment '班级编号,主键',
name varchar(30) not null comment '班级名称'
);
这个是主表。
再创建从表:学生表,并设置外键关联班级
create table if not exists stu (
id int primary key comment '学生编号',
name varchar(30) not null comment '学生姓名',
class_id int comment '所属班级编号',
foreign key (class_id) references myclass(id)
);
这个是从表。
查看

由表结构可知:外键用于建立从表(stu)与主表(myclass)的关联关系 ,并通过强制约束保证数据参照完整性。从表class_id作为外键,其取值必须在主表主键id中存在(或为 NULL),以此从数据库层面杜绝非法关联数据,确保两张表的业务逻辑一致性。
数据插入测试
-- 向班级表插入合法数据
mysql> insert into myclass values(10, 'C++大牛班'),(20, 'java大神班');
-- 向学生表插入合法数据(班级存在)
mysql> insert into stu values(100, '张三', 10),(101, '李四',20);
-- 插入不存在的班级 30,违反外键约束,插入失败
mysql> insert into stu values(102, 'wangwu',30);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))
-- 插入 NULL 表示暂未分配班级,允许插入
mysql> insert into stu values(102, 'wangwu', null);
可知:
- 外键约束会严格校验从表数据,插入主表中不存在的关联值时,操作直接失败,保证了业务数据的合法性。
- 外键字段允许为 NULL,表示该记录暂未关联主表数据,不违反参照完整性。
- 外键从数据库层面强制维护表与表之间的关联关系,有效避免无效、错误的脏数据产生。
外键的意义 :如果不使用外键,两张表只在逻辑上相关,数据库不会做任何校验,就可能出现脏数据。外键的本质,是把业务层的关联规则交给数据库强制校验,从底层保证数据一致性,避免业务逻辑漏洞产生无效数据。
外键的本质,是把业务层的关联规则交给数据库强制校验,从底层保证数据一致性,避免业务逻辑漏洞产生无效数据。
MySQL 表约束全章总结
本章系统讲解了 MySQL 中核心的表约束类型,从基础字段约束到表间关联约束,完整覆盖了数据合法性校验的核心手段:
- 基础字段约束 :
NOT NULL强制字段非空、DEFAULT预设默认值、COMMENT标注字段含义、ZEROFILL实现数字格式化显示,从字段层面规范数据存储; - 唯一标识约束 :
PRIMARY KEY作为表的唯一标识(非空 + 唯一,一张表仅一个,支持单列 / 复合主键),搭配AUTO_INCREMENT自动生成自增 ID,是表设计的标准规范;UNIQUE KEY解决多字段唯一性需求,允许空值,适配业务字段的唯一性校验; - 表间关联约束 :
FOREIGN KEY建立主从表的关联关系,强制校验从表外键数据的合法性,从数据库层面杜绝脏数据,保证数据的参照完整性与业务逻辑一致性。
约束是数据库数据合法性的最后防线,合理使用约束能从根源上避免脏数据、提升数据质量,是 MySQL 表设计的核心必备技能。
以上就是本次 MySQL 表约束的全部内容,若大家后续有补充内容,或发现文中疏漏、错误,欢迎在评论区一起交流探讨~感谢各位的阅读!