MySQL: MySQL约束与数据完整性详解

最后更新:2026-08-26

约束是数据完整性的守护者——防止脏数据进入数据库。

本课系统讲解所有约束类型及管理。

100%
graph TB
    A[MySQL 约束] --> B[PRIMARY KEY<br/>主键约束]
    A --> C[FOREIGN KEY<br/>外键约束]
    A --> D[UNIQUE<br/>唯一约束]
    A --> E[NOT NULL<br/>非空约束]
    A --> F[CHECK<br/>检查约束]
    C --> C1[CASCADE]
    C --> C2[SET NULL]
    C --> C3[RESTRICT]

1. 你将学到


2. 一个真实的故事

(1) 痛点:脏数据无处不在

订单系统运行半年后,数据质量触目惊心:出现了负数金额的订单、没有关联客户的"幽灵订单"、同一个用户名注册了 5 个账号。开发团队试图在应用层校验,但前后端代码分散,总有漏洞。一次促销活动中,黑客绕过前端校验提交了负数金额,直接造成财务损失。

(2) 约束的解法

在数据库层面强制数据完整性——PRIMARY KEY 保证唯一、FOREIGN KEY 保证关联、CHECK 保证范围、UNIQUE 保证不重复。

维度 应用层校验 数据库约束
防护范围 仅本应用 所有连接来源
可绕过性 前端/接口可绕 不可绕过
维护成本 分散在多处 集中在表定义
数据安全 中等 最高

3. 五大约束总览

约束 作用 允许 NULL 允许重复
PRIMARY KEY 唯一标识每行
FOREIGN KEY 关联其他表
UNIQUE 值不能重复
NOT NULL 不能为 NULL
CHECK 满足条件

4. PRIMARY KEY 主键

▶ 示例:主键约束

SQL
-- 单列主键
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50)
);

-- 复合主键
CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);
▶ 试一试

5. FOREIGN KEY 外键

▶ 示例:外键与级联

SQL
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    customer_id INT,
    amount DECIMAL(10,2),
    FOREIGN KEY (customer_id) REFERENCES customers(id)
        ON DELETE CASCADE      -- 删除客户时级联删除订单
        ON UPDATE CASCADE      -- 更新客户ID时级联更新
);

-- 级联选项
-- CASCADE: 同步删除/更新
-- SET NULL: 设为 NULL
-- RESTRICT: 拒绝操作(默认)
-- NO ACTION: 同 RESTRICT
▶ 试一试

6. UNIQUE 唯一约束

▶ 示例:唯一约束

SQL
-- 单列唯一
CREATE TABLE users (
    id INT PRIMARY KEY,
    email VARCHAR(100) UNIQUE,
    username VARCHAR(50) UNIQUE
);

-- 复合唯一
CREATE TABLE user_roles (
    user_id INT,
    role_id INT,
    UNIQUE (user_id, role_id)
);
▶ 试一试

7. NOT NULL 非空约束

▶ 示例:非空约束

SQL
CREATE TABLE products (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    description TEXT  -- 允许 NULL
);
▶ 试一试

8. CHECK 检查约束(8.0+)

▶ 示例:CHECK 约束

SQL
CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    age INT CHECK (age >= 18 AND age <= 65),
    salary DECIMAL(10,2) CHECK (salary > 0),
    email VARCHAR(100) CHECK (email LIKE '%@%.%')
);

-- 添加 CHECK 约束
ALTER TABLE employees ADD CONSTRAINT chk_age CHECK (age >= 18);

-- 删除 CHECK 约束
ALTER TABLE employees DROP CHECK chk_age;
▶ 试一试

9. 约束管理

▶ 示例:添加/删除约束

SQL
-- 添加主键
ALTER TABLE users ADD PRIMARY KEY (id);

-- 添加外键
ALTER TABLE orders ADD CONSTRAINT fk_customer 
FOREIGN KEY (customer_id) REFERENCES customers(id);

-- 添加唯一约束
ALTER TABLE users ADD UNIQUE (email);

-- 删除外键
ALTER TABLE orders DROP FOREIGN KEY fk_customer;

-- 删除唯一约束
ALTER TABLE users DROP INDEX email;
▶ 试一试

❓ 常见问题

Q 外键会影响性能?
A 会有一点(写入时检查约束),但保证数据完整性。高并发可在应用层检查。
Q NULL 和 UNIQUE 的关系?
A UNIQUE 允许多个 NULL(MySQL 中 NULL != NULL)。
Q CHECK 约束能用函数吗?
A MySQL 8.0+ 支持 CHECK 中使用表达式,但不支持子查询。
Q CHECK 约束在 5.7 有效吗?
A 无效。MySQL 5.7 只语法接受 CHECK 但不执行,8.0.16+ 才真正强制执行。
Q 删除外键后数据还在吗?
A 在。删除外键只删约束关系,不删除任何数据。

📖 小节


📝 作业

  1. 基础题(难度⭐):创建带完整约束的用户表。

  2. 进阶题(难度⭐⭐):创建外键并测试级联删除。

  3. 挑战题(难度⭐⭐⭐):设计一个带 CHECK 约束的产品表,验证约束生效。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏