这是个典型的“看起来很小,实际会影响长期架构”的决策点。
每次新起一个项目,都会有个“要不要用数据库枚举”的问题。这个问题的答案可能会影响未来几年的开发效率和维护成本。
一、先给结论
枚举(ENUM)适合:稳定、小范围、强约束的字段
不适合:会变化、需要扩展、涉及业务逻辑的字段
二、用枚举的好处
当然也不是说它一无是处,还是有一些好处的:
1️⃣ 数据层强约束(防脏数据)
status ENUM('draft', 'published', 'archived')
数据库直接帮你兜底:
- ❌ 不可能插入
abc - ❌ 不可能拼错
publised
👉 比 varchar 靠谱很多
2️⃣ 节省存储
比如在 MySQL 里 ENUM 实际存的是 索引值:
'draft' → 1
'published' → 2
所以:
- 占用空间小
- 查询快一点(但别神话这个优势)
3️⃣ 语义清晰(数据库层)
你一看表结构就知道:
status ENUM(...)
比 status VARCHAR(50) 更有“约束力”。
三、坏处(这是重点)
1️⃣ ❌ 修改成本非常高(致命点)
加一个值:
ALTER TABLE posts MODIFY status ENUM(...)
问题:
- 锁表(大表直接炸)
- migration 很重
- CI/CD 风险高
👉 这是最大的问题,没有之一
2️⃣ ❌ 不利于扩展(你这个项目很可能会踩)
比如你现在:
draft / published
未来可能变:
draft / reviewing / rejected / scheduled / published
甚至:
- 多语言
- 自定义状态
- SaaS 不同租户不同状态
👉 ENUM 直接卡死你
3️⃣ ❌ 和业务逻辑耦合太深
你在:
- 后端
- 前端
- API
都要同步这套枚举。
一旦改:
👉 全链路改动
4️⃣ ❌ 不利于生态
在开源社区,数据库 ENUM 可能会导致:
- 贡献者不敢改
- 维护者不敢改
因为改了可能会破坏现有用户。
还有一个隐藏风险是:不同数据库对 ENUM 的支持不一致。
- MySQL 有原生 ENUM 类型
- PostgreSQL 也支持,但语法不同、迁移流程更复杂
- SQLite 没有 ENUM,通常会退化为 TEXT
所以使用 ENUM 将你的数据层约束与数据库厂商绑定,移植成本高。
例如 Laravel 推荐:
- PHP Enum(8.1+)
- 常量类
- 配置驱动
而不是 DB ENUM。
现在数据库都已经支持 ENUM,但编程语言本身的枚举类型更灵活:你可以把业务规则放到代码层控制、版本管理和测试,避免频繁修改迁移文件。
比如:
enum PostStatus: string {
case Draft = 'draft';
case Published = 'published';
}
👉 更灵活、可扩展、可测试
四、在 Laravel 项目里的“最佳实践”
🥇 推荐方案(最通用)
- ✅ 数据库用
varchar - ✅ 业务用 PHP Enum
$table->string('status');
enum PostStatus: string {
case Draft = 'draft';
case Published = 'published';
}
Model:
protected $casts = [
'status' => PostStatus::class,
];
👉 优点:
- DB 不锁死
- 代码强类型
- 易扩展
- 易维护
迁移提示:从 ENUM 到 varchar
如果你当前正用 ENUM,可以按以下步骤安全迁移:
- 新增
varchar字段并写入enum值(不更新旧字段) - 应用代码改为读写新字段,并在测试中验证行为一致
- 执行
CHECK约束(可选) - 删除老
enum字段
这种方式避免一次性 ALTER TABLE 卡表,同时保留回滚路径。
平衡本地化与扩展的场景建议
- 推荐:状态类型由应用层定义(Enum、常量类、字典表)
- 可接受:极其稳定、完全不可变的技术字段(如
gender、device_type) - 不推荐:经常变化或多租户自定义的业务字段
🥈 如果需要更强扩展性
通常像 SaaS 产品,状态可能会被客户自定义,这时候:
👉 用“字典表”
statuses
- id
- code
- name
- tenant_id(可选)
👉 适合:
- 可配置状态
- 多租户
- 后台可编辑
🥉 ENUM 适合的场景
只有这种情况我才建议你用:
- 极其稳定
- 不会扩展
- 纯技术字段
比如:
gender: male / female
device_type: ios / android / web
五、一句经验总结
ENUM 是“现在很爽,未来很痛”的设计