民宿/网约房数字化升级:基于智能锁的身份核验与远程授权解决方案
2026/6/12 22:07:51
以下是MySQL 表的约束(Constraints)一文详解,适合作为“第六节”的核心内容,内容覆盖 MySQL 8.0+ 主流用法,包含原理、语法、常见场景、注意事项和面试/生产高频考点。
| 约束类型 | 英文名称 | 作用 | 是否允许 NULL | 是否允许重复 | 是否可以有多列 | 是否可以自定义名称 | 是否可以延迟检查 |
|---|---|---|---|---|---|---|---|
| 主键约束 | PRIMARY KEY | 唯一标识每一行,唯一 + 非空 | 否 | 否 | 可以(复合主键) | 可以 | 否 |
| 唯一约束 | UNIQUE | 列/列组合值唯一 | 可以 | 否 | 可以 | 可以 | 否 |
| 非空约束 | NOT NULL | 该列不允许为空 | 否 | 可以 | — | 不可 | 否 |
| 默认值约束 | DEFAULT | 未指定值时自动填充默认值 | — | — | — | 不可 | 否 |
| 检查约束 | CHECK | 自定义条件校验(MySQL 8.0.16+ 真正生效) | — | — | 可以 | 可以 | 否 |
| 外键约束 | FOREIGN KEY | 维护参照完整性 | 可以 | 可以 | 可以 | 可以 | 可以(延迟) |
-- 方式1:列级定义(最常见)CREATETABLEusers(idBIGINTNOTNULLAUTO_INCREMENTPRIMARYKEY,usernameVARCHAR(50)NOTNULL);-- 方式2:表级定义(适合复合主键)CREATETABLEorder_items(order_idBIGINTNOTNULL,item_idBIGINTNOTNULL,quantityINTNOTNULL,PRIMARYKEY(order_id,item_id));-- 方式3:已有表添加主键(必须先满足唯一+非空)ALTERTABLEusersADDPRIMARYKEY(id);重要特性:
PRIMARY)-- 列级CREATETABLEemployees(emp_noINTPRIMARYKEY,emailVARCHAR(100)UNIQUENOTNULL);-- 表级(复合唯一)CREATETABLEuser_roles(user_idBIGINTNOTNULL,role_idBIGINTNOTNULL,UNIQUEKEYuk_user_role(user_id,role_id));-- 已有表添加ALTERTABLEemployeesADDUNIQUEKEYuk_email(email);ALTERTABLEuser_rolesADDUNIQUE(user_id,role_id);关键区别vs 主键:
| 项目 | PRIMARY KEY | UNIQUE |
|---|---|---|
| 允许 NULL | 否 | 是(但 NULL 不算重复) |
| 数量限制 | 一个表只能一个 | 可以多个 |
| 是否自动创建索引 | 是(聚簇索引) | 是(普通唯一索引) |
| 名字 | 固定为 PRIMARY | 可自定义 |
面试常问:一张表可以有多个 UNIQUE 约束,但只能有一个 PRIMARY KEY。
CREATETABLEproducts(idINTPRIMARYKEYAUTO_INCREMENT,nameVARCHAR(100)NOTNULL,priceDECIMAL(10,2)NOTNULLDEFAULT0.00,created_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP);注意:
ALTER TABLE ... MODIFY COLUMN可以添加/移除 NOT NULL-- 普通默认值statusTINYINTNOTNULLDEFAULT0,-- 表达式默认值(MySQL 8.0.13+)created_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,updated_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,-- 虚拟列默认值(函数表达式)full_nameVARCHAR(101)GENERATED ALWAYSAS(CONCAT(first_name,' ',last_name))STORED,MySQL 8.0+ 支持的 DEFAULT 表达式:
CREATETABLEemployees(idINTPRIMARYKEYAUTO_INCREMENT,ageTINYINTUNSIGNEDNOTNULL,salaryDECIMAL(10,2)NOTNULL,-- 方式1:列级CHECK(age>=18ANDage<=65),-- 方式2:表级(可跨列)CONSTRAINTchk_salaryCHECK(salary>=3000ANDsalary<=100000));-- 已有表添加ALTERTABLEemployeesADDCONSTRAINTchk_ageCHECK(ageBETWEEN18AND65);重要提醒:
-- 先创建主表CREATETABLEdepartments(dept_idINTPRIMARYKEYAUTO_INCREMENT,dept_nameVARCHAR(50)NOTNULLUNIQUE);-- 再创建从表CREATETABLEemployees(emp_idINTPRIMARYKEYAUTO_INCREMENT,dept_idINTNOTNULL,nameVARCHAR(50)NOTNULL,FOREIGNKEY(dept_id)REFERENCESdepartments(dept_id)-- 更完整的写法(推荐生产环境)CONSTRAINTfk_emp_deptFOREIGNKEY(dept_id)REFERENCESdepartments(dept_id)ONDELETERESTRICT-- 默认行为ONUPDATECASCADE);外键动作选项(ON DELETE / ON UPDATE):
| 选项 | 含义 | 典型使用场景 |
|---|---|---|
| RESTRICT | 禁止删除/更新主表记录(默认) | 严格保护数据完整性 |
| CASCADE | 级联删除/更新 | 主从数据必须保持一致(如订单-明细) |
| SET NULL | 主表删除/更新后从表对应字段置 NULL | 可选关联关系 |
| NO ACTION | 同 RESTRICT(MySQL 中等价) | — |
外键使用建议(生产环境):
-- 查看表所有约束SHOWCREATETABLEemployees\G-- 查看所有外键SELECT*FROMinformation_schema.REFERENTIAL_CONSTRAINTSWHERETABLE_SCHEMA='your_db';-- 删除约束(必须知道约束名)ALTERTABLEemployeesDROPFOREIGNKEYfk_emp_dept;ALTERTABLEemployeesDROPPRIMARYKEY;ALTERTABLEemployeesDROPINDEXuk_email;ALTERTABLEemployeesMODIFYCOLUMNemailVARCHAR(100)NULL;-- 移除 NOT NULL-- 添加约束(已有数据要满足条件)ALTERTABLEemployeesADDUNIQUE(email);ALTERTABLEemployeesADDCONSTRAINTpk_empPRIMARYKEY(emp_id);希望这份总结能帮你彻底搞懂 MySQL 表的约束体系。
需要我继续补充外键级联实际案例、CHECK 约束性能测试、无主键表 vs 有主键性能对比等更深入的内容吗?