Immich 数据库迁移踩坑实录:改了 schema,Postgres 为什么纹丝不动
2026/9/10 14:52:29 网站建设 项目流程

Immich 数据库迁移踩坑实录:改了 schema,Postgres 为什么纹丝不动

【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher

Immich 数据库迁移的核心是"声明与落库解耦":表结构写在代码里,真正改数据库的是迁移文件。改完server/src/schema/tables/之后,必须用 sql-tools 生成迁移并登记 ORDER 清单,Postgres 才会有变化。

改了表字段,Postgres 里为什么查不到:先做 sql-tools 迁移生成

在 Immich 里,全部表结构都在server/src/schema/tables/中以声明式 API 定义,枚举和数据库函数也在同目录。这里有个反直觉的点:这些文件无论怎么改,Postgres 都不会动一下。它们只是"图纸",真正执行的是迁移文件,而迁移文件要靠 sql-tools 显式生成:

mise //server:migrations generate AddUserAvatarColorColumn # 产出带毫秒时间戳前缀的 .ts 文件,如 1745244781846-AddUserAvatarColorColumn.ts

//server:前缀表示在 monorepo 根目录下执行 server 包的任务,任务本质是把sql-tools -u <连接串> migrations <子命令>包了一层;连接串默认指向本地 Docker 里的 Postgres,可用DB_URL覆盖。

生成的迁移文件里有两个函数:up负责加列等 DDL 并把存量数据回填进新列,down负责反向操作。真实的回填 SQL 长这样:

UPDATE "users" SET "avatarColor" = "user_metadata"."value" -> 'avatar' ->> 'color' FROM "user_metadata" WHERE "users"."id" = "user_metadata"."userId" AND "user_metadata"."key" = 'preferences';

你会发现,生成的文件并不直接落在最终目录,需要手动把它挪进server/src/schema/migrations/。当前已有 90 多个文件,清一色<毫秒时间戳>-<名称>命名,目录内字典序就是执行顺序。

这是第一个坑:生成这一步完全靠手工。只改表定义的话,服务照常启动、代码照常编译,但数据库里并没有新列,直到某个功能去查这列才报错。

两个分支各加一个迁移,合并后起不来:ORDER 清单在防什么

你可能会问:文件名都带时间戳了,顺序自动就能排,还需要一个清单文件干嘛?

答案藏在合并场景里。A、B 两个分支各加一个迁移,合并后真正的冲突发生在server/src/schema/migrations/ORDER上——每行是一个迁移名,像排队叫号的小票。它被故意设计成会产生 git 冲突:逼你显式决定谁先谁后。只靠时间戳文件的话,两个分支会"静默地"以错误顺序合并,后执行的 DDL 若引用了先执行才该创建的表,服务直接起不来,而且合并时没有任何预警。

代价是几行冲突噪音,买到的是顺序的确定性。所以新增迁移后必须执行这条命令:

mise //server:migrations sync-order # 把新迁移追加登记到 ORDER 清单末尾

提交代码时,一定把 ORDER 清单一起提交。因为执行流程严格按清单走,清单里没有的迁移文件,等于不存在。

想撤销刚才的加列操作:Immich 迁移回滚怎么做

想验证down是否真的可逆,或者迁移写错了,不用手写 SQL 删列:

mise //server:migrations revert

这条命令执行最近一次已应用迁移的down(),数据库回到迁移前的状态。在server目录里也能直接跑npm run migrations:xxx脚本,最常用的三个是migrations:run(执行全部未应用的)、migrations:revert(回滚最近一次)、migrations:sync-order(登记进清单)。

两个提醒。其一,revert 只该在本地开发、测试库上用;生产库动手前务必人工核对down逻辑并先备份。其二,生成的down不保证无损——加列若伴随数据回填,回滚会丢掉新回填的数据,DDL 可逆性本来就是单向的。

本地库被改乱了:schema 漂移检测怎么查,怎么一键重建

实际会碰到:调试时手改过一张表、切完分支本地库和代码对不上、误删了迁移文件。这时别从日志一条条查,先用仓库内置的 schema-check 服务命令(实现在server/src/commands/schema-check.ts)做一次 schema 漂移检测,它把每个迁移分成三种状态:已应用、已删除(数据库里有、磁盘文件没了)、缺失(磁盘有、还没应用)。检测到漂移会列出漂移项并附上修复 SQL——源码里标着 "Use at your own risk",人工确认后再用。

本地库已经没法精确定位问题时,别花时间排查,直接跑mise //server:schema-reset重建。该任务先执行DROP SCHEMA public CASCADE清空 public 库,再按 ORDER 清单重放全部 90 多个迁移,得到一份与代码完全一致的干净库。命令会清空全部数据,仅限本地开发环境,生产库千万别碰。

看到 deleted 状态时,先找回丢失的迁移文件,别急着改数据库。

CI 上 verify-order 报错:你漏了 sync-order

server 的 checklist 任务在单测与中测之后跑 verify-order,核对磁盘迁移文件与 ORDER 清单是否完全一致。CI 上它挂了,原因几乎只有一个:迁移文件提交了,清单没提交,也就是漏了 sync-order。

补救很简单:补跑mise //server:migrations sync-order,把清单提交上去。

开发环境其实很宽容——server 会监听*.ts文件变更自动重启,启动流程本身就包含"执行所有未应用迁移"。本地改完只要重启/重载一次,新迁移就会立刻落到本地数据库,不用手动 run。整条链路长这样:

如果你只记住三件事

改完表定义必须生成迁移,代码里的 schema 不会自己落到数据库。新迁移要立刻 sync-order 并把 ORDER 清单一起提交,别赌合并不冲突。本地库乱了,dev 库放心 schema-reset;生产库永远先备份再谈操作。

【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询