您的位置:时间博客>优词记>不写 migration:我把数据库 schema 当作唯一真相源

不写 migration:我把数据库 schema 当作唯一真相源

这是背单词小程序「优词记 Pro」技术复盘的第四篇。前面聊过后端只有一条路由,今天聊另一个反常规的决定:项目里没有一行 migration,所有模型代码从数据库反向生成

migration 解决的问题,和它带来的问题

migration 的价值在于让 schema 变更可版本化、可回放,团队协作时很有必要。但在单人或小团队项目里,我实际感受到的是另一面:改一个字段要写 up/down、跑迁移、再手动同步 Model 里的 fillable 和注释——三个地方描述同一件事,时间久了必然漂移。代码里的模型定义和数据库真实结构不一致,才是更隐蔽的坑。

所以我反过来做:数据库 schema 是唯一真相源,代码是它的投影。改表直接在数据库改,然后跑一条命令让代码追上来:

php bin/hyperf.php entity

一张表生成两个文件

这条命令读取 information_schema.COLUMNS,为每张表生成两个文件:

Entity(列定义层):抽象类,包含表名常量 TABLE、每一列的 C_* 名称常量,以及一个 COLUMN 元数据数组——列的中文名、类型、验证规则、关系声明、是否文件字段、展示格式都在里面。这些信息大部分直接来自数据库的列注释和类型定义。

Model(查询层):继承 Entity,承载查询构建方法(如 getListByPagegetListByKeyword)。生成器只搭骨架,业务查询方法手写在这里,重新生成 Entity 不会覆盖它们。

这个拆分是关键:机器生成的和人手写的严格分文件存放,再生成永远是安全操作。

元数据驱动带来的复利

把列信息集中到 COLUMN 数组后,很多通用能力可以直接从元数据推导出来:

  • 参数验证:验证规则跟着列定义走,控制器里一行 validate() 就完成校验,规则不用重复维护

  • 关系映射:表间关系在 COLUMN 里声明式定义,基类 getRelation() 动态解析,不用每个 Model 手写关联方法

  • 静态分析:列名全部常量化(C_USER_ID 而不是字符串 'user_id'),拼错列名在 phpstan 阶段就报错,IDE 补全和重构也全覆盖

代价说在前面

这套做法不适合所有项目。最大的代价是丢掉了 schema 变更历史:数据库改了什么、什么时候改的,代码仓库里看不到,需要靠定期导出 SQL 备份来兜底。其次是环境同步依赖纪律——多环境部署时表结构要人工对齐,没有 migration 的自动回放。如果你的团队超过三五个人、或者需要频繁搭建新环境,老老实实写 migration 更稳。对我这种数据库结构相对稳定、单人维护的项目,它省下的同步成本是实打实的。

产品本体是个背单词小程序,微信搜「优词记 Pro」可以体验。明天聊一个具体业务问题:打卡日历的「连续学习天数」为什么最终下沉到了数据库层计算,欢迎关注。


转载请注明本文标题和链接:《 不写 migration:我把数据库 schema 当作唯一真相源

相关推荐

网友评论 0

未登陆 表情
Ctrl+Enter快速提交