一、约束是什么&怎么分类
约束是写在表结构里、由存储引擎强制执行的“数据完整性规则”。和“应用层校验”的本质区别是:约束在数据库这一层兜底,应用绕不过去。
从功能维度,MySQL8分为三大类:

二、约束详解
1、NOT NULL -- 禁止空值
最基础的域约束,保证列必须有值。
CREATE TABLE user ( id BIGINT PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) -- 允许为 NULL );
注意:NOT NULL 与“空字符串”不是一回事,‘ ’是合法的非NULL值。
2、Default -- 默认值
插入未指定该列时自动填入。MySQL8支持表达式默认值(DEFAULT(expr)),这是8.0相对旧版本的增强。
CREATE TABLE orders ( id BIGINT PRIMARY KEY, created_at DATETIME DEFAULT (NOW()), -- 8.0 表达式默认值 status VARCHAR(20) DEFAULT 'PENDING' );
3、UNIQUE -- 唯一但允许空
保证列 值 不重复,但 NULL 例外:
CREATE TABLE user ( id BIGINT PRIMARY KEY, email VARCHAR(100) NOT NULL UNIQUE );
4、PRIMARY KEY -- 主键
= NOT NULL + UNIQUE ,且全表唯一、只能有一个(但可以是多列组合)
CREATE TABLE order_item ( order_id BIGINT, product_id BIGINT, qty INT, PRIMARY KEY (order_id, product_id) -- 复合主键 );
5、FOREIGN KEY -- 外键
保证子表某列的值必须在父表存在,维护表间引用一致性:
CREATE TABLE customer ( id BIGINT PRIMARY KEY, name VARCHAR(50) NOT NULL ); CREATE TABLE `order` ( id BIGINT PRIMARY KEY, customer_id BIGINT NOT NULL, amount DECIMAL(10,2), CONSTRAINT fk_order_cust FOREIGN KEY (customer_id) REFERENCES customer(id) ON DELETE CASCADE ON UPDATE RESTRICT );
6、CHECK -- 取值范围校验(8.0真正生效)
CREATE TABLE product ( id BIGINT PRIMARY KEY, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL, CONSTRAINT chk_price CHECK (price > 0), CONSTRAINT chk_stock CHECK (stock >= 0) ); -- 以下插入将被拒绝: INSERT INTO product VALUES (1, -5, 10); -- ERROR 3819 (HY000): Check constraint failed
三、深入理解
1、约束不等于索引,但强相关
PRIMARY KEY 和 UNIQUE 会自动创建唯一索引(InnoDB 下)。所以唯一约束的查找走索引,速度快。
FOREIGN KEY 不会自动给子表外键建索引,但要求父表被引用列必须有索引(通常是主键/唯一键)。
子表外键列建议手动加索引,否则级联更新/删除会全表扫描父表、易锁表。
2. NULL 在 UNIQUE 中的特殊性
InnoDB 的 UNIQUE 索引允许插入多个 NULL(因为 NULL 被视为"未知",彼此不相等,所以不违反唯一)。
这与主键不同——主键列本身隐含 NOT NULL,不可能有 NULL。
CREATE TABLE t (a INT UNIQUE); INSERT INTO t VALUES (NULL), (NULL); -- 成功,两条 NULL 都被接受