MySQL – 约束

【MySQL 笔记】约束(Constraints)完整详解(2026 年生产视角)

约束是数据库在数据层面强制执行规则的核心机制,它能极大提高数据质量、减少脏数据、降低业务代码的校验负担。

MySQL(InnoDB 引擎)支持的约束类型如下,按重要程度和使用频率排序:

一、MySQL 主要约束类型对比表

约束类型关键字强制规则是否允许 NULL是否允许重复每表数量限制是否自动创建索引级别生产使用频率(2026)
非空约束NOT NULL值不能为空列级★★★★★
默认值约束DEFAULT未提供值时自动填充列级★★★★☆
唯一约束UNIQUE值全局唯一(NULL 除外)是(多 NULL)是(唯一索引)列级/表级★★★★★
主键约束PRIMARY KEY唯一 + 非空 + 表唯一标识1是(聚集索引)列级/表级★★★★★(必有)
自增属性AUTO_INCREMENT自动递增(通常配合主键)1(每表)列级★★★★★
外键约束FOREIGN KEY参照完整性(必须存在于主表)是(视情况)是(普通索引)表级★★★★☆(谨慎)
检查约束CHECK自定义条件表达式列级/表级★★★★☆(8.0.16+)

二、各种约束写法对比(列级 vs 表级)

CREATE TABLE users (
    -- 列级约束(简单、常见)
    id          BIGINT UNSIGNED AUTO_INCREMENT,
    username    VARCHAR(50) NOT NULL UNIQUE,
    email       VARCHAR(120) UNIQUE,
    phone       VARCHAR(20) DEFAULT '未设置',
    age         TINYINT UNSIGNED CHECK (age >= 0 AND age <= 150),
    status      TINYINT UNSIGNED DEFAULT 1 NOT NULL,
    created_at  DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
    updated_at  DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),

    -- 表级约束(可以起名字、支持复合约束)
    PRIMARY KEY (id),                                 -- 表级主键
    CONSTRAINT uk_users_email         UNIQUE (email), -- 表级唯一
    CONSTRAINT uk_users_phone_region  UNIQUE (phone, country_code), -- 复合唯一
    CONSTRAINT chk_users_age          CHECK (age >= 18 OR is_minor = 1),
    CONSTRAINT chk_users_status       CHECK (status IN (0,1,2,9))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

三、约束行为与注意事项速查

约束类型插入/更新 NULL 时插入重复值时删除主表记录时(有外键)修改主表主键时性能开销排序生产推荐写法
NOT NULL报错允许极低几乎所有重要字段都加
UNIQUE允许(多 NULL)报错中等手机号、邮箱、订单号
PRIMARY KEY报错报错中等(聚集索引)每张表必须有
AUTO_INCREMENTBIGINT UNSIGNED + PRIMARY KEY
FOREIGN KEY允许(若允许 NULL)取决于 ON DELETE取决于 ON UPDATE中~高小中型项目谨慎,大表慎用
CHECK按条件按条件低~中8.0.16+ 推荐用(状态、范围)

四、最常见的生产约束组合模板(2026 年推荐)

CREATE TABLE orders (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '订单主键',
    order_no        VARCHAR(32) NOT NULL UNIQUE COMMENT '订单编号',
    user_id         BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
    total_amount    DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '订单总金额',
    status          TINYINT UNSIGNED NOT NULL DEFAULT 0 
                    CHECK (status IN (0,1,2,3,4,5,9)) COMMENT '订单状态:0-待支付...',
    created_at      DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
    updated_at      DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',

    -- 外键(视项目规模可选)
    CONSTRAINT fk_orders_user 
        FOREIGN KEY (user_id) REFERENCES users(id)
        ON DELETE RESTRICT          -- 防止误删用户导致订单孤立
        ON UPDATE CASCADE,

    INDEX idx_user_id (user_id),
    INDEX idx_status_created (status, created_at)
) ENGINE=InnoDB 
  DEFAULT CHARSET=utf8mb4 
  COLLATE=utf8mb4_unicode_ci 
  COMMENT='订单主表';

五、生产中最容易踩的约束坑(血泪经验)

  1. 忘记 NOT NULL → 出现大量空值,业务判断爆炸
  2. 用 INT 做主键/用户ID → 超过 42 亿就溢出(用 BIGINT UNSIGNED)
  3. 外键加在高并发大表上 → 插入/删除性能急剧下降,甚至死锁
  4. 没给外键字段建索引 → InnoDB 会自动建,但名字不一致时维护麻烦
  5. CHECK 约束写在 5.7 或 8.0.15 以下 → 只是语法糖,不生效
  6. 主键不是自增 → 分布式 ID 场景除外,否则容易出现主键冲突
  7. 所有字段都加 DEFAULT NULL → 违背 NOT NULL 的初衷
  8. 忘记写 COMMENT → 半年后没人敢改表

六、约束管理常用命令(开发/运维必备)

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

-- 查看外键信息
SELECT * FROM information_schema.table_constraints 
WHERE table_name = 'orders' AND constraint_type = 'FOREIGN KEY';

-- 删除外键(必须知道约束名)
ALTER TABLE orders DROP FOREIGN KEY fk_orders_user;

-- 删除主键(极少用,大表慎重)
ALTER TABLE old_table DROP PRIMARY KEY;

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

下一期预告建议:MySQL 索引全家桶(上)—— 聚簇索引 vs 非聚簇索引 + 最左前缀 + 覆盖索引 + 索引失效场景

你目前项目里约束用得最多的类型是哪些?
有没有遇到过外键性能问题、CHECK 不生效、或者唯一约束冲突的真实案例?
欢迎留言,我们可以针对性继续深入~

祝大家建表加约束一步到位,数据干净又安全!🛡️

文章已创建 5186

发表回复

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

相关文章

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

返回顶部