好的 Schema 让非法状态难以进入数据库。字段类型、NOT NULL、唯一键和检查约束不是“DBA 细节”,而是跨应用实例共享的最后一道数据契约。
Table of contents
Open Table of contents
先写业务不变量
订单金额不得为负、邮箱不可重复、订单必须属于已存在用户。把能由数据库稳定表达的规则写成约束:
amount DECIMAL(12,2) NOT NULL,
UNIQUE KEY uk_users_email (email),
CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id),
CONSTRAINT chk_orders_amount CHECK (amount >= 0)
约束失败应映射为明确业务错误,不能吞掉异常后继续提交。
常用类型怎么选
- 金额用
DECIMAL,Java 用BigDecimal,避免二进制浮点误差。 - 时间点统一时区语义。
TIMESTAMP与DATETIME的转换、范围和存储语义不同,先按业务定义再选。 - 状态值可用受控字符串或小整数代码;不要用 Java
enum.ordinal(),枚举重排会改变含义。 - 大文本、图片和视频通常放对象存储,表里保存对象键、大小、校验和与权限元数据。
字符串索引受字符集、排序规则和长度影响。utf8mb4 能表达完整 Unicode;排序规则决定大小写和重音是否相等。账号、展示名和机器标识符不一定应该使用相同规则。
NULL、默认值和软删除
NULL 表示未知或不存在,不等于空字符串或 0。若业务必填就用 NOT NULL。默认值应是正确业务默认,而不是为了少处理空值。
软删除会让唯一键、查询条件、索引选择性和数据生命周期变复杂。先问是否真的需要恢复与审计;需要时明确 deleted_at 语义、所有查询过滤和最终物理清理机制。
完整示例见建表脚本。
下一步
继续阅读06-14 MySQL 全局性能,从单条 SQL 扩展到整台实例的资源竞争。