Immich 数据库迁移实战:5 条命令搞定 schema 变更、回滚与漂移检测
【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher
改完 Immich 的表定义、重启服务端,查询却还在报"字段不存在"——问题多半出在 Immich 数据库迁移这一步没走对。这篇文章用 5 条 mise migrations 命令,带你覆盖 sql-tools 迁移生成、ORDER 清单登记、启动自动应用、迁移回滚与 schema 漂移检测的完整路径。
改完表定义、重启服务,查询为何还报"字段不存在"?
先说一个几乎每个 Immich 贡献者都踩过的坑:你在 server/src/schema/tables 里给 asset 表加了一列,保存、重启服务端,满怀期待地发一条新查询——报错:column does not exist。
数据库没坏,代码也没写错。真相是:代码里写的 schema 和 Postgres 里真实存在的 schema,是两套东西。前者只描述"应该长什么样",后者只认"真正执行过的 DDL"。你改了图纸,但没人去工地施工,楼当然不会自己长出新楼层。
官方文档 database-migrations.md 的全部篇幅,都在讲怎么把"图纸"变成"工地"。下面按你动手的顺序拆。
声明式表定义与迁移文件:sql-tools 如何生成 DDL
Immich 的 schema 代码分两层,职责互不重叠。
第一层是声明式表定义,集中在 server/src/schema/tables(约 64 个表定义文件,外加 enums.ts、functions.ts 负责枚举和数据库函数)。它回答"数据库应该长什么样"——类比装修图纸:尺寸、水电都画好了,但图纸本身盖不起房子。
第二层是迁移文件,放在 server/src/schema/migrations,每个文件导出 up() 和 down() 两个异步函数,用 kysely 的 sql 标签模板执行原生 SQL。它回答"怎么把旧库改到位"——这是施工单:加哪根梁、拆哪堵墙、拆错了怎么复原。
而把图纸和施工单对起来的,是 @immich/sql-tools:它比对声明式定义与真实数据库的差异,自动产出 DDL 写进迁移文件。换句话说,你只负责改图纸,工具负责出具施工单,你再把关执行。
一次迁移的完整走位:从 generate 到 sync-order
一次迁移有四个动作:生成、审阅、落位、登记。
生成。仓库根目录执行:
mise //server:migrations generate <migration-name>//server:前缀表示在 monorepo 根目录执行 server 包的任务(定义在 server/mise.toml),最终展开为sql-tools -u <连接串> migrations generate ...。连接串看环境变量 DB_URL,不设置就默认连本地 Docker 里的开发库 postgres://postgres:postgres@localhost:5432/immich。产出的文件带毫秒时间戳前缀,例如 1745244781846-AddUserAvatarColorColumn.ts——时间戳的作用就是让字典序等于执行顺序。
审阅。打开文件重点看三处:up() 生成的 DDL 是否符合预期、存量数据回填有没有漏、down() 能否安全走回去。举个例子,AddUserAvatarColorColumn 的 up 除了加列,还要把老数据从 user_metadata 的 JSON 字段回填进新列;down 只负责删列。
落位。generate 不会把文件直接放进最终目录,需要手动移到 server/src/schema/migrations。那里已有近百个迁移,从 1744910873969-InitialMigration 一路排到最新,命名统一为<毫秒时间戳>-<PascalCase名称>.ts。
登记。移完文件,补上最后一条命令:
mise //server:migrations sync-order它把新迁移追加进 ORDER 清单。这份清单为什么值得单独一节?往下看。
ORDER 清单:一份故意制造冲突的文件
举个例子:你拉了 feature-a 给 asset 表加索引,同事拉了 feature-b 新建 plugin 表,两边各生成一个带时间戳的迁移文件。如果顺序只靠目录里的文件名,两个分支合并时 git 一声不吭——文件互不冲突,但执行顺序可能错了:先跑的迁移若引用了对方还没建的表,服务启动直接失败,而且这种失败往往要等部署后才暴露。
Immich 的解法是把顺序写进一份 git 跟踪的清单 migrations/ORDER:每行一个迁移名(去掉 .ts 后缀),新迁移靠 sync-order 追加。于是两个分支各自改了 ORDER 文件,合并时必然冲突,逼你亲自拍板谁先谁后。
说白了,这是用"冲突噪音"换"顺序确定性"的有意取舍:多花三十秒解冲突,换来合并后迁移顺序 100% 可预期。所以 ORDER 必须和迁移文件放在同一个 commit 提交,漏掉它,下一关 CI 会拦住你。
生效、校验与迁移回滚:revert 回滚最近一次变更
先说结论:贯穿日常的其实就 5 条命令——generate、run、revert、sync-order、verify-order,前两条上面已经见过。
迁移怎么生效?开发环境什么都不用手动做。服务端监听 *.ts 变更自动重启,而启动流程本身就包含"运行所有未应用的迁移"——改完 schema、登记完 ORDER,重启 server,新迁移就落到本地库了。想显式跑一次,run 子命令会执行全部未应用的迁移。
这里容易踩坑的是校验:CI 的 checklist 任务会在单测、中测之后执行 verify-order,核对磁盘文件与 ORDER 清单是否完全一致,专抓"文件移过去了、忘 sync-order"这类漏提交。
回滚用 🔧 revert:
mise //server:migrations revert它执行最新一条迁移的 down(),把 schema 恢复到迁移前。开发新迁移时这是检验 down 逻辑的标准姿势:先 run 再 revert,确认结构和数据都能复原。
server/package.json 里还有一组等价的 npm scripts,措辞不同但一一对应:
| 子命令 | 什么时候用 |
|---|---|
| generate | 比对 schema 与数据库差异,自动产出迁移 DDL |
| run | 执行所有未应用的迁移 |
| revert | 回滚最近一次迁移,检验 down() |
| sync-order | 把新迁移登记进 ORDER 清单 |
| verify-order | 校验清单与磁盘文件一致(CI 使用) |
排错工具箱:schema 漂移检测与本地重置
本地库被改乱了吗?仓库内置 schema-check 服务命令(实现见 schema-check 源码),逻辑像一份体检报告:核对"磁盘迁移历史"与"数据库真实状态",给每个迁移判三种状态之一——
- applied:已应用,正常路径;
- deleted:数据库里执行过,磁盘上文件却没了;
- missing:磁盘上有,数据库里还没执行。
发现漂移时,它列出漂移项(借 sql-tools 的 asHuman 渲染),并附上一段自动生成的修复 SQL。源码特意标了 "Use at your own risk!"——那段 SQL 仅供参考,涉及删表删列时,执行前必须人工确认。
再往下就是"核按钮":schema-drop 与 schema-reset 两个任务,同样定义在 server/mise.toml。
[tasks."schema-drop"] run = { task = "migrations query 'DROP schema public cascade; CREATE schema public;'" }schema-reset 则是先 drop、再 migrations run,按 ORDER 重放全部迁移,得到与代码完全一致的干净库。⚠️ 两个任务都会清空全部数据,仅限本地开发环境使用;生产环境严禁照搬——生产要改 schema,只有正规的迁移流程一条路。
提交前自查:6 条快速核对项
- 声明式定义(tables 等)改完并保存
- 跑过 generate,up()/down() 逐行审过(含数据回填与可回退性)
- 迁移文件已移入 server/src/schema/migrations
- sync-order 已执行,ORDER 与迁移文件同 commit 提交
- 重启本地 server 验证自动应用,必要时 revert 回滚、schema-check 查漂移
- verify-order 通过
【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考