【MySQL 笔记】表的约束(上)—— 基础约束详解
表的约束(Constraints) 是数据库设计中最核心的部分之一,它从数据库层面强制规定数据的合法性、一致性和完整性。
MySQL 主要支持以下几种约束(InnoDB 引擎下最完整):
| 约束类型 | 英文关键词 | 作用 | 是否允许 NULL | 是否允许重复 | 每表可有几个 | 级别(列级/表级) | 是否自动创建索引 | MySQL 版本特性 |
|---|---|---|---|---|---|---|---|---|
| 非空约束 | NOT NULL | 字段值不能为空 | 否 | 是 | 多 | 列级 | 否 | 全版本 |
| 默认值约束 | DEFAULT | 未指定值时自动填充 | — | — | 多 | 列级 | 否 | 全版本(8.0+ 支持函数如 NOW()) |
| 唯一约束 | UNIQUE [KEY] | 字段值全局唯一(除 NULL 外) | 是(多 NULL) | 否 | 多 | 列级 / 表级 | 是(唯一索引) | 全版本 |
| 主键约束 | PRIMARY KEY | 唯一 + 非空 + 表唯一标识 | 否 | 否 | 1 | 列级 / 表级 | 是(聚集索引) | 全版本 |
| 自增属性 | AUTO_INCREMENT | 自动递增(通常配合主键) | — | — | 1(每表) | 列级 | — | 全版本 |
| 检查约束 | CHECK | 自定义表达式检查 | — | — | 多 | 列级 / 表级 | 否 | 8.0.16+ 真正强制执行 |
| 外键约束 | FOREIGN KEY | 参照完整性(关联其他表主键/唯一键) | 是(视情况) | — | 多 | 表级 | 是(普通索引) | 全版本(InnoDB) |
说明:
- 主键 = NOT NULL + UNIQUE + 表唯一
- 唯一键 ≠ 主键(唯一键允许 NULL,主键不允许)
- CHECK 在 MySQL 8.0.16 之前只是语法糖(不强制执行),8.0.16+ 才真正生效
二、创建表时添加约束的两种写法
- 列级约束(直接写在列定义后面)
- 表级约束(写在所有列后面,可起约束名)
CREATE TABLE users (
id INT AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20) DEFAULT '未填写',
age TINYINT UNSIGNED CHECK (age >= 0 AND age <= 150),
status TINYINT DEFAULT 1,
-- 表级约束示例
CONSTRAINT pk_users PRIMARY KEY (id),
CONSTRAINT uk_users_email UNIQUE (email), -- 可重复定义,但没必要
CONSTRAINT chk_users_status CHECK (status IN (0,1,2))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
三、每种约束详细示例 & 常见写法
1. 非空约束(NOT NULL)
username VARCHAR(50) NOT NULL COMMENT '用户名',
- 插入/更新时必须提供值,否则报错:
Field 'username' doesn't have a default value
2. 默认值(DEFAULT)
-- 常量默认值
status TINYINT DEFAULT 1,
-- MySQL 8.0+ 支持表达式/函数(推荐)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
3. 唯一约束(UNIQUE)
-- 列级
email VARCHAR(100) UNIQUE,
-- 表级(复合唯一)
CONSTRAINT uk_user_phone UNIQUE (phone, country_code),
- 允许多个 NULL(NULL 不算重复)
- 自动创建唯一索引
4. 主键约束(PRIMARY KEY)
-- 单列主键(最常见)
id BIGINT AUTO_INCREMENT PRIMARY KEY,
-- 复合主键(表级)
PRIMARY KEY (user_id, order_id),
- 自动创建聚集索引(InnoDB)
- 每表只能有一个主键
5. 自增(AUTO_INCREMENT)
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
- 必须是整数类型 + 主键(或唯一键 + NOT NULL)
- 起始值默认 1,可修改:
ALTER TABLE t AUTO_INCREMENT = 1000;
6. 检查约束(CHECK)—— 8.0.16+
-- 列级
score TINYINT CHECK (score BETWEEN 0 AND 100),
-- 表级(多列关联)
CONSTRAINT chk_salary CHECK (salary > bonus),
- 插入/更新时不满足条件会报错
7. 外键约束(FOREIGN KEY)—— 下期重点
-- 简单写法
user_id BIGINT,
FOREIGN KEY (user_id) REFERENCES users(id),
-- 带级联行为(推荐生产使用)
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE -- 主表删,从表也删
ON UPDATE CASCADE, -- 主表改,从表跟着改
常见级联选项:
- CASCADE:级联
- SET NULL:置空
- RESTRICT / NO ACTION:禁止(默认)
- SET DEFAULT:设默认值
四、约束相关常用操作
-- 查看表约束
SHOW CREATE TABLE users\G
-- 查看外键
SELECT * FROM information_schema.table_constraints
WHERE table_name = 'orders';
-- 删除约束(需知道约束名)
ALTER TABLE users DROP FOREIGN KEY fk_orders_user;
ALTER TABLE users DROP PRIMARY KEY;
ALTER TABLE users DROP INDEX uk_email;
五、约束设计建议(2026 年生产经验)
- 几乎所有表都应该有主键(推荐自增或雪花ID)
- 业务唯一字段用 UNIQUE(如手机号、邮箱、订单号)
- 重要字段加 NOT NULL + DEFAULT
- 外键谨慎使用(性能开销大,小中型项目可考虑逻辑外键)
- CHECK 约束多用在 8.0+ 项目(年龄、状态枚举等)
- 约束名要规范:
pk_表名、uk_表名_字段、fk_从表_主表、chk_表名_条件
下一期预告:表的约束(下)—— 外键详解 + 级联行为 + 约束 vs 索引区别 + 生产中常见坑
有哪种约束在项目里踩过坑,或者想看具体的外键级联演示,欢迎留言~
祝大家建表时约束加得又全又稳!🛡️