数据库约束是嵌入在表结构中的规则集合,用于限制存入表中的数据范围和关系,从而保证数据的完整性(Integrity)。这种完整性包含三个维度:
人工校验数据完整性不仅效率低下,更难以应对高频次的数据操作。而数据库约束将这种校验工作"自动化"和"底层化",带来三大核心价值:
约束通常与表结构一同定义,作用于特定列或多列组合。不同数据库系统对约束的支持存在细微差异,但核心类型和实现原理基本一致。
定义:限制列不能存储NULL值,强制该字段必须有具体内容。
应用场景:所有必须填写的信息,如用户姓名、订单编号、身份证号等。在业务逻辑中,这些字段如果缺失会导致数据不完整。
创建方式:
-- 建表时添加非空约束
CREATE TABLE student (
id INT NOT NULL,
name VARCHAR(50) NOT NULL -- 用户名不能为空
);行为特性:
ERROR 1048 (23000): Column 'username' cannot be nullDESCRIBE命令查看列的非空属性,"Null"列显示"NO"表示非空约束生效:

DESCRIBE命令查看列的非空属性,"Null"列显示"NO"表示非空约束生效

这个时候null列: NO表示当前列不能为空 YES 表示当前列可以为空
注意事项:

定义:保证列中每一条记录的值都是唯一的,不允许重复(NULL值除外)。 也就是某列的值在整个表中不能重复,比如身份证号,学号
应用场景:需要唯一标识但不作为主键的字段,如手机号、邮箱地址、工号等。这些字段需要唯一性但可能存在业务上的变更需求。
引例:

不加唯一约束的时候,可能出现了编号相同,但是人名不同的情况,不符合逻辑
创建方式:
-- 建表时添加唯一约束
CREATE TABLE employee (
id INT unique, --学号唯一
name VARCHAR(50)
);

第二次直接再去插入相同的id的记录,就会报错了,因为ID的列那就不唯一了 但是对于的NULL可以重复插入,不受唯一约束的影响,因为null与null两者判断是为假
行为特性:
ERROR 1062 (23000): Duplicate entry '13800138000' for key 'phone'定义:当插入记录时未指定该列的值,数据库自动使用预设的默认值填充
应用场景:需要设置默认状态的字段,如用户注册时的默认角色、订单的默认状态、创建时间的自动填充等 当为某列设置了默认约束的时候,如果不给这个列指定值才会使用默认约束
创建方式:
-- 建表时添加默认值约束
CREATE TABLE student (
id BIGINT UNIQUE,
name VARCHAR(50) DEFAULT '无名氏'
);
inser into student (id,name) values (2,NULL);
这时仅指定了id,这是name列使用的默认值填充 且会发现序列号为2的时候,它的名字是NULL
虽然有指定的默认约束,但是当我们手动指定那个这一列的值为NULL时,插入的值依然是NULL,因为这个NULL 是我们自己手动指定的,也可以理解我们想要的值
行为特性:
CURRENT_TIMESTAMP)常见误区:
NOW())而非固定字符串定义:非空约束(NOT NULL)和唯一约束(UNIQUE)的组合,用于唯一标识表中的每条记录,有助于更容易更快速地找到表中的一个特定的记录
主键约束的列既是非空的也是唯一的
应用场景:每张表都应该有主键,用于记录的唯一标识和快速定位,如用户ID、商品ID、订单ID等。
示例:
-- 单字段主键
CREATE TABLE student (
id INT PRIMARY KEY, -- 主键约束
-- id INT NOT NULL UNIQUE 这种写完也是主键约束
sn INT UNIQUE,
name VARCHAR(20) NOT NULL,
);把id的列识别为非空且唯一,这时候可以通过查看表结构

这个时候我们可以看到表结构中id列是键值情况为主键而不是UNI 所以是id列知道那个非空和唯一的约束,列被标示为了一个PRI,表示它是一个主键

我们可以看到写入数据之后的两种约束同时生效
主键约束帮我们校验了非空和唯一,这两个校验在写入数据的时候对效率是有一定影响的,但是比起不做校验来说,这个性能消耗还是可以承担的,并且主键对索引有着非常重要的作用,所以最好还是建议为每张表定义一个主键
-- 自增主键(最常用方式)
create table student(
id bigint primary key auto_increment,
sn int unique,
name varchar(20) default '无名氏'
);
auto_increment 表示的是自增类型 作用是:让数据库帮我们去维护逐渐的增长,不用程序员自己去计算了,在插入的时候,先找到最大的值,然后在这个基础上加1,去生成一个新的值,做为新一个数据行的主键(id列)值
insert into student values (null,10001,'张三');
insert into student values (null,10002,'李四');
全列插入: 在写入数据时,不具体指定主键列的值,而是用NULL代替
当设置了自增主键之后,发现写入null时,也可以成功的插入数据;这里并不是说把这个null写入数据库,而是说让数据库帮我们去处理这个列的值(自增操作)
insert into student (sn,name) values (10003,'王五'),(10004,'赵六');
主键值可以指定值,只要不重复就可以
insert into student (id,sn,name) values (100,10100,'钱七');
-- 这个时候再去添加一条数据
insert into student (sn,name) values (10101,'王二麻子');
但是我们通过发现:我们新添加的数据行的id是101 在最大值的基本上再去加1,那么主键值在数据表中所以有可能是不连续的

类似于雪花算法,后续会在数据库的深入学习会给大家进行讲解
一个表中不允许有两个主键
create table test(
id bigint primary key,
sn bigint primary key
);
错误:不能定义多个主键在一张数据表中
但是一个主键同时可以包含多个列(复合主键)
-- 复合主键(多字段组合)
create table stu1(
id bigint,
name varchar(20),
mail varchar(50),
primary key(id,name)
);
这个时候都id,name两列中的主键都是PRI:表示当表定义了复合主键,在唯一教研室,只有复合主键中的所有的列都相同才被判定为相同
再次进行插入数据记录:
insert into stu1 values (1,'张三','zs@qq.com');主键的值是定义复合主键时,多个列值的组合,复合主键一般用-进行连接,进而表示复合主键

这个时候名字和编号都相同,就会判定主键是相同的
insert into stu1 values (1,'李四','ls@qq.com');
这种情况下,虽然编号相同,但是姓名不同,是可以插入成功的
核心特性总结:
复合主键解析: 复合主键由多个字段组合而成,仅当所有字段值都相同时才判定为重复。典型应用于多对多关系表:
-- 允许插入(组合值不同)
INSERT INTO student_course VALUES (1, 101, 90);
INSERT INTO student_course VALUES (1, 102, 85);
INSERT INTO student_course VALUES (2, 101, 92);
-- 禁止插入(组合值重复)
INSERT INTO student_course VALUES (1, 101, 88); -- 报错主键设计原则:
定义:维护两个表之间的参照关系,确保从表(子表)的列值必须在主表的参照列中存在。保证一个表中的数据匹配另一个表中的值的参照完整性
应用场景:存在关联关系的表结构,如订单表关联用户表、学生表关联班级表、商品表关联分类表等。

解释: 表中某个列的值,必须是另一张表中的主键列,或是唯一约束列的值,也就是当前表中的值在另一张表中必须存在,且还要满足主键或是唯一约束
示例: 建立关联关系,那么关联关系的主外键的数据类型要与目标表中的数据类型要保持一致
-- 1. 先创建主表(被参照表)
CREATE table class(
id BIGINT PRIMARY KEY auto_increment,
name VARCHAR(20)
);
-- 2. 创建从表(子表)并添加外键约束
CREATE TABLE student(
id BIGINT PRIMARY KEY auto_increment,
name VARCHAR(20) not null,
class_id BIGINT
);
-- 建立关联关系,那么关联关系的主外键的数据类型要与目标表中的数据类型要保持一致
-- 为已有表添加外键约束
ALTER TABLE student
ADD CONSTRAINT fk_student_class
FOREIGN KEY (class_id) REFERENCES class(id);
但是此时的创建的两张表并没有设置了主外键的关系,所以这个时候我们可以会插入错误的数据

这个时候写入了一条学生记录,设置了不存在的班级编号,现在数据是可以写入成功的,所以需要设置`主外键
外键用于关联其他表的主键或者唯一键,语法:
foreign key (字段名) references 主表(列);-- 1. 先创建主表(被参照表)
CREATE table class(
id BIGINT PRIMARY KEY auto_increment,
name VARCHAR(20)
);
-- 2. 创建从表(子表)并添加外键约束
CREATE TABLE student(
id BIGINT PRIMARY KEY auto_increment,
name VARCHAR(20) not null,
class_id BIGINT
foregin key (class_id) references class(id) -- 这个时候指定并设置外键
);

insert into student (name,class_id) values ('张三',1),('李四',1),('王五',2),('赵六',3)
这个时候写入正确数据的时候是可以插入成功的 这个时候写入一个主表的不存在的id记录

通过外键约束,保证数据的完整性和关系的正确性 在目前来说,我们用代码层面去进行校验,而不是让数据库自己去进行校验 是因为数据库自己校验的过程越多,性能便消耗的越严重,对于数据的保存的功能会有所影响,所以用代码进行剥离开,从而减少数据库的校验
删除主表中的数据

当子表中存在对主表的依赖的时候,那么能不能删除主表中相应的记录?
我们首先进行直接删除主表的的记录:
DELETE FROM class WHERE id=4; -- 报错:被student表引用
如果删除主表中的记录,就要子表中不能有对该条记录的依赖,也就意味要先删除子表中的记录,再去删除主表中记录
DELETE FROM student WHERE class_id=4;
DELETE FROM class WHERE id=4;
参照规则:
外键动作处理:
当主表记录被删除或更新时,可以通过ON DELETE和ON UPDATE指定处理策略:
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
class_id INT,
FOREIGN KEY (class_id) REFERENCES class(id)
ON DELETE CASCADE -- 主表记录删除时,从表关联记录也删除
ON UPDATE SET NULL -- 主表记录更新时,从表关联字段设为NULL
);常用策略包括:
CASCADE:级联操作(主表变动,从表相应变动)SET NULL:主表变动时,从表外键设为NULLRESTRICT:禁止操作(默认行为)NO ACTION:不做处理(多数数据库等同于RESTRICT)外键使用争议: 尽管外键能保证数据参照完整性,但在高并发系统中常被禁用,原因包括:
替代方案是在应用程序层面实现参照完整性校验,通过业务逻辑保证数据关联正确。
定义:限制列值必须满足指定的条件(如范围、格式等)。
应用场景:需要对列值进行范围或格式限制的场景,如年龄必须为正数、成绩在0-100之间、性别只能是"男"或"女"等。
创建方式:
-- 建表时添加检查约束
CREATE TABLE test (
id INT ,
gender VARCHAR(1) ,
CHECK (gender IN ('男', '女')), -- 性别只能是男女
);
数据库兼容性:
使用建议:
通过数据库系统表可以查询表中已定义的约束:
-- MySQL中查看约束
SELECT
CONSTRAINT_NAME,
COLUMN_NAME,
CONSTRAINT_TYPE
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE
TABLE_NAME = 'student';-- 删除主键约束
ALTER TABLE student DROP PRIMARY KEY;
-- 删除唯一约束
ALTER TABLE student DROP INDEX emp_no; -- 唯一约束以索引形式存在
-- 删除外键约束
ALTER TABLE student DROP FOREIGN KEY fk_student_class;
-- 删除检查约束
ALTER TABLE student DROP CONSTRAINT chk_age;
-- 删除默认值约束(通过修改列定义)
ALTER TABLE student ALTER COLUMN status DROP DEFAULT;约束虽然保障了数据完整性,但也会带来一定的性能开销:
性能优化建议:
-- 临时禁用外键约束
SET FOREIGN_KEY_CHECKS = 0;
-- 执行批量插入操作
INSERT INTO student (...) VALUES (...), (...), ...;
-- 恢复外键约束
SET FOREIGN_KEY_CHECKS = 1;fk_从表名_主表名规则,便于识别ON DELETE和ON UPDATE策略,避免意外数据丢失MySQL 5.7中用枚举(ENUM)替代CHECK约束:
CREATE TABLE student (
gender ENUM('男', '女') NOT NULL -- 等效于CHECK约束
);数据库约束是保障数据质量的核心机制,合理使用约束可以显著减少数据错误,降低系统维护成本,但过度使用也会带来性能损耗;在实际开发中,应根据系统规模和业务特点灵活选择约束策略;随着数据库技术的发展,新型数据库对约束的支持更加灵活,结合了关系型数据库的完整性保障和NoSQL的高扩展性。但无论技术如何变化和迭代,"数据完整性"始终是数据库设计的核心原则,而约束正是实现这一原则的基础工具。 本文的内容就先到这里了,如果有哪些地方的不足,欢迎大家在评论区中进行指正与批评,谢谢大家!