mysql中创建表时添加唯一约束最省事,支持列级(如username varchar(50) not null unique)和表级(如unique key uk_email (email))两种写法,自动创建唯一索引,允许多个null值,重复插入报错“duplicate entry”;已有表可用alter table ... add unique补充,复合约束需unique (a, b)定义。

创建表时直接加 UNIQUE 最省事
只要字段在建表阶段就能确定要防重复,就别等后续再改——直接在 CREATE TABLE 里写死约束。MySQL 会自动为该字段创建唯一索引,插入重复值时立刻报错:Duplicate entry 'xxx' for key 'xxx'。
常见写法有两种:
-
username VARCHAR(50) NOT NULL UNIQUE:列级写法,简洁,适合单字段 -
UNIQUE KEY uk_email (email):表级写法,显式命名索引(uk_email),方便以后删改
注意:UNIQUE 允许多个 NULL 值,和 PRIMARY KEY 不同。比如 email VARCHAR(100) UNIQUE,允许用户不填邮箱,但填了就不能重复。
ALTER TABLE ... ADD UNIQUE 给已有表补约束
线上表没加唯一约束?别硬编码业务层去查重,直接用 ALTER TABLE 补上。但必须先清理脏数据,否则语句会失败。
执行前务必确认:
- 目标字段当前无重复值(用
SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1检查) - 字段允许为
NULL的话,得接受多个NULL并存(MySQL 视每个NULL为不同值) - 如果想命名约束便于管理,写成
ADD CONSTRAINT uk_phone UNIQUE (phone);不命名则 MySQL 自动生成类似email_2a3b4c的内部名
示例:ALTER TABLE users ADD UNIQUE (phone);
复合唯一约束怎么写:多字段组合才算重复
单字段不够判重?比如「一个学生只能选一门课一次」,就得靠两个字段一起约束。这时不能对 student_id 或 course_id 单独加 UNIQUE,而要用括号包住组合:UNIQUE (student_id, course_id)。
关键点:
- 顺序有影响:
(a,b)和(b,a)是两个不同索引,查询条件必须按左前缀匹配才走索引 - 只对「所有字段值完全相同」才拒绝插入,
(1,2)和(1,3)不冲突 - 建表时写:
UNIQUE KEY uk_stu_course (student_id, course_id);已有表用ALTER TABLE t ADD UNIQUE (student_id, course_id)
加了唯一约束,插入重复数据怎么处理
约束本身只负责报错,不决定你怎么应对。业务代码里得配合具体 SQL 语句策略:
-
INSERT IGNORE INTO:遇到重复直接跳过,不报错,但也不告诉你跳了——适合「存在即忽略」场景 -
INSERT ... ON DUPLICATE KEY UPDATE:重复时转为更新,比如登录次数 +1,注意要明确指定更新哪些字段 -
REPLACE INTO:本质是DELETE + INSERT,会改变自增 ID、触发DELETE相关逻辑,慎用 - 纯
INSERT+ 捕获错误码1062:最可控,但需应用层做重试或降级
所有这些的前提都是字段上已有 PRIMARY KEY 或 UNIQUE 索引,否则不会触发对应行为。
真正容易被忽略的是:唯一约束依赖索引实现,而索引会影响 INSERT/UPDATE 性能,尤其在大表上加约束前,最好评估下现有数据量和写入频率。











