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%

🙏 帮我们做得更好

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

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