约束
约束是数据库对数据合法性施加的规则,用来把结构边界和可表达的业务不变量下沉到数据库层。
#concept
#growing
#backend
#database
#sql
[!info] related notes
约束
一句话定义
约束是数据库主动拒绝非法持久化状态的规则;它让“哪些数据允许存在”成为 Schema 的一部分,而不只停留在应用代码或接口文档里。
常见完整性约束
NOT NULL
要求列必须有值:
name TEXT NOT NULL
NULL 表示缺失/未知值,不等于空字符串、0 或 false。
UNIQUE
要求候选值不能重复:
email TEXT UNIQUE
多个字段组合唯一时使用联合唯一约束:
UNIQUE (user_id, slug)
CHECK
要求每一行满足可由数据库表达的布尔条件:
score INTEGER CHECK (score BETWEEN 0 AND 100)
PRIMARY KEY
为一行定义主身份,要求唯一且非空。
FOREIGN KEY
保证跨表引用指向真实存在的候选键,并可定义删除/更新时的引用行为。
DEFAULT 不是完整性约束
DEFAULT 经常和约束一起出现在 DDL 中,但更准确地说,它是“未提供值时使用什么默认表达式”的列定义规则:
status TEXT DEFAULT 'active'
它不会像 CHECK、UNIQUE 或 FOREIGN KEY 那样拒绝不符合某个不变量的显式输入。因此不要把“有默认值”和“数据被约束为这个值”混为一谈。
Application Validation 与数据库约束
两层不是二选一:
Application
→ 尽早校验输入
→ 返回友好、领域化错误
Database
→ 最终拒绝非法持久化状态
例如应用可以先检查邮箱是否已存在,但并发请求仍可能同时通过检查;真正保证最终不存在重复邮箱的是数据库 UNIQUE。
什么规则适合下沉
适合数据库约束的通常是跨所有写入入口都必须成立、并且数据库能够局部判断的持久化不变量,例如:
- 必填;
- 唯一;
- 引用必须存在;
- 数值范围;
- 同一行字段之间的简单关系。
复杂权限、调用外部服务、跨长流程状态机等规则通常仍属于应用层。
边界与易混淆点
- 约束不是“多写几个 SQL 关键字”,而是数据质量和并发正确性的最后防线。
- 主键和外键本身就是约束的具体类型。
- 数据类型也限制可存储值,但通常和完整性约束分开讨论。
- 能在数据库层强制的关键不变量,不应只依赖某一条 Service 代码路径。