【MySQL】第六节—一文详解 | 表的约束

以下是 MySQL 表的约束(Constraints) 一文详解,适合作为“第六节”的核心内容,内容覆盖 MySQL 8.0+ 主流用法,包含原理、语法、常见场景、注意事项和面试/生产高频考点。

一、MySQL 表约束总览(2025–2026 主流)

约束类型英文名称作用是否允许 NULL是否允许重复是否可以有多列是否可以自定义名称是否可以延迟检查
主键约束PRIMARY KEY唯一标识每一行,唯一 + 非空可以(复合主键)可以
唯一约束UNIQUE列/列组合值唯一可以可以可以
非空约束NOT NULL该列不允许为空可以不可
默认值约束DEFAULT未指定值时自动填充默认值不可
检查约束CHECK自定义条件校验(MySQL 8.0.16+ 真正生效)可以可以
外键约束FOREIGN KEY维护参照完整性可以可以可以可以可以(延迟)

二、每种约束详细语法与实战说明

1. 主键约束(PRIMARY KEY)

-- 方式1:列级定义(最常见)
CREATE TABLE users (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL
);

-- 方式2:表级定义(适合复合主键)
CREATE TABLE order_items (
    order_id BIGINT NOT NULL,
    item_id  BIGINT NOT NULL,
    quantity INT NOT NULL,
    PRIMARY KEY (order_id, item_id)
);

-- 方式3:已有表添加主键(必须先满足唯一+非空)
ALTER TABLE users ADD PRIMARY KEY (id);

重要特性

  • 自动创建唯一索引(名为 PRIMARY
  • InnoDB 表必须有主键(推荐自增 BIGINT)
  • 没有主键的表会隐式创建 6 字节 ROWID 作为聚簇索引(不推荐)

2. 唯一约束(UNIQUE)

-- 列级
CREATE TABLE employees (
    emp_no   INT PRIMARY KEY,
    email    VARCHAR(100) UNIQUE NOT NULL
);

-- 表级(复合唯一)
CREATE TABLE user_roles (
    user_id BIGINT NOT NULL,
    role_id BIGINT NOT NULL,
    UNIQUE KEY uk_user_role (user_id, role_id)
);

-- 已有表添加
ALTER TABLE employees ADD UNIQUE KEY uk_email (email);
ALTER TABLE user_roles ADD UNIQUE (user_id, role_id);

关键区别 vs 主键:

项目PRIMARY KEYUNIQUE
允许 NULL是(但 NULL 不算重复)
数量限制一个表只能一个可以多个
是否自动创建索引是(聚簇索引)是(普通唯一索引)
名字固定为 PRIMARY可自定义

面试常问:一张表可以有多个 UNIQUE 约束,但只能有一个 PRIMARY KEY。

3. 非空约束(NOT NULL)

CREATE TABLE products (
    id          INT PRIMARY KEY AUTO_INCREMENT,
    name        VARCHAR(100) NOT NULL,
    price       DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    created_at  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

注意

  • 已有表添加 NOT NULL 时,列中不能有 NULL 值,否则报错
  • ALTER TABLE ... MODIFY COLUMN 可以添加/移除 NOT NULL

4. 默认值(DEFAULT)

-- 普通默认值
status TINYINT NOT NULL DEFAULT 0,

-- 表达式默认值(MySQL 8.0.13+)
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

-- 虚拟列默认值(函数表达式)
full_name VARCHAR(101) GENERATED ALWAYS AS (CONCAT(first_name,' ',last_name)) STORED,

MySQL 8.0+ 支持的 DEFAULT 表达式

  • CURRENT_TIMESTAMP
  • NOW()
  • UUID()
  • (expression) AS …

5. 检查约束(CHECK)—— MySQL 8.0.16+ 真正生效

CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    age TINYINT UNSIGNED NOT NULL,
    salary DECIMAL(10,2) NOT NULL,

    -- 方式1:列级
    CHECK (age >= 18 AND age <= 65),

    -- 方式2:表级(可跨列)
    CONSTRAINT chk_salary CHECK (salary >= 3000 AND salary <= 100000)
);

-- 已有表添加
ALTER TABLE employees
ADD CONSTRAINT chk_age CHECK (age BETWEEN 18 AND 65);

重要提醒

  • MySQL 5.7 及之前版本:CHECK 语法可以写,但不生效(只是语法通过)
  • 8.0.16 之后才真正校验
  • 性能开销较小,但复杂 CHECK 会影响写入性能

6. 外键约束(FOREIGN KEY)——参照完整性

-- 先创建主表
CREATE TABLE departments (
    dept_id   INT PRIMARY KEY AUTO_INCREMENT,
    dept_name VARCHAR(50) NOT NULL UNIQUE
);

-- 再创建从表
CREATE TABLE employees (
    emp_id    INT PRIMARY KEY AUTO_INCREMENT,
    dept_id   INT NOT NULL,
    name      VARCHAR(50) NOT NULL,

    FOREIGN KEY (dept_id) REFERENCES departments(dept_id)

    -- 更完整的写法(推荐生产环境)
    CONSTRAINT fk_emp_dept 
    FOREIGN KEY (dept_id) 
    REFERENCES departments(dept_id)
    ON DELETE RESTRICT          -- 默认行为
    ON UPDATE CASCADE
);

外键动作选项(ON DELETE / ON UPDATE)

选项含义典型使用场景
RESTRICT禁止删除/更新主表记录(默认)严格保护数据完整性
CASCADE级联删除/更新主从数据必须保持一致(如订单-明细)
SET NULL主表删除/更新后从表对应字段置 NULL可选关联关系
NO ACTION同 RESTRICT(MySQL 中等价)

外键使用建议(生产环境)

  • 小型项目、性能敏感表 → 可以不建外键,用业务代码保证
  • 中大型业务系统、数据质量要求高 → 强烈建议建外键 + 合适的 ON DELETE/UPDATE 策略
  • 外键会创建索引(如果从表字段没有索引,会自动创建)

三、约束的增删改查操作总结

-- 查看表所有约束
SHOW CREATE TABLE employees\G

-- 查看所有外键
SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS
WHERE TABLE_SCHEMA = 'your_db';

-- 删除约束(必须知道约束名)
ALTER TABLE employees DROP FOREIGN KEY fk_emp_dept;
ALTER TABLE employees DROP PRIMARY KEY;
ALTER TABLE employees DROP INDEX uk_email;
ALTER TABLE employees MODIFY COLUMN email VARCHAR(100) NULL;  -- 移除 NOT NULL

-- 添加约束(已有数据要满足条件)
ALTER TABLE employees ADD UNIQUE (email);
ALTER TABLE employees ADD CONSTRAINT pk_emp PRIMARY KEY (emp_id);

四、面试/生产高频问题 20 条(建议背熟)

  1. 主键和唯一约束的本质区别是什么?
  2. 一张表可以有几个主键?几个唯一约束?
  3. MySQL 外键一定需要创建索引吗?
  4. ON DELETE CASCADE 和 ON DELETE SET NULL 的适用场景分别是什么?
  5. MySQL 什么时候真正开始校验 CHECK 约束?
  6. 没有主键的 InnoDB 表底层是怎么存储的?
  7. 复合主键的顺序对查询性能有影响吗?
  8. 外键约束会影响 insert/update/delete 的性能吗?
  9. 如何批量删除外键约束?
  10. DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 的典型使用场景?

希望这份总结能帮你彻底搞懂 MySQL 表的约束体系。

需要我继续补充外键级联实际案例CHECK 约束性能测试无主键表 vs 有主键性能对比等更深入的内容吗?

文章已创建 4206

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部