Immich 数据库迁移实战:从加一列到一键回滚
【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher
Immich 是一款自托管的照片/视频管理项目,服务端把所有业务数据存在 PostgreSQL 里。只要改过表结构,必须走一次数据库迁移,数据库才会真正生效。这篇文章从"想给表加一列字段"这个最常见的需求切入,把生成迁移、审读内容、登记 ORDER 清单、自动应用、回滚与漂移排查的整条链路走一遍,并附上命令速查表和提交前检查清单。
Immich schema 变更之前:分清 schema、migrations、ORDER 的分工
拿装修打比方。server/src/schema/tables/下的表定义文件(约 64 个表,外加负责枚举与数据库函数的enums.ts、functions.ts)是设计图纸,描述"数据库应该长什么样";migrations/目录里一个个<时间戳>-<名称>.ts文件是施工方案,up()负责把现有库改成图纸的样子,down()负责退回去;migrations/ORDER则是施工排期表,固定各套方案的先后顺序。
@immich/sql-tools是连接图纸和工地的勘察队:它拿声明式 schema 去对照真实数据库,从差异里自动生成迁移 DDL,运行时再按 ORDER 的顺序执行。这个工具在仓库锁文件中锁定为 0.6.3。
- schema(图纸):
server/src/schema/下的声明式定义,描述目标状态; - migrations(施工方案):每次变更一个
.ts,毫秒时间戳前缀保证字典序即执行顺序; - ORDER(排期表):受 git 跟踪的清单,决定"谁先谁后",是多分支合并不乱序的关键。
Immich 迁移实战:给表一列字段的完整流程
生成迁移文件的正确姿势
先说结论:在 monorepo 根目录执行mise //server:migrations generate AddNewField就能生成迁移文件。
//server:前缀表示在 monorepo 根目录下执行server包的任务(mise.toml声明了monorepo_root = true)。server/mise.toml里这个任务实际展开为sql-tools -u <连接串> migrations generate <name>:连接串取自环境变量DB_URL,不设置时默认指向postgres://postgres:postgres@localhost:5432/immich,也就是本地 Docker 开发环境里的 Postgres。
生成的文件以<毫秒时间戳>-<PascalCase名称>.ts命名,先落在 server 目录下,此时还没进最终目录,审读通过后再移过去。
审读 up 与 down:三个必查点
打开生成的文件,依次查三件事。第一,DDL 是否符合预期:列名、类型、可空性都对不对,是不是加在了你打算改的表上。第二,存量数据要不要回填:新列加完,老行都是空的,想从已有字段填充就得在 ADD 之后自己补 UPDATE,工具生成的 DDL 只改结构、不动数据。第三,down能不能安全回退:涉及删列、覆盖数据这类不可逆步骤,必须显式接受数据丢失才允许合入。
拿仓库里早期的1744991379464-AddNotificationsTable来说,up是一套建表语句,down就是对应的删表,方向严格相反。仓库里还有一些空操作占位迁移,比如1750323941566-UnsetPrewarmDimParameter,它的up/down什么都不做,存在的意义只是维持 ORDER 清单与磁盘文件的一一对应,别随手删。
登记 ORDER 清单:别漏了这一步
审读完成后,把迁移文件移进server/src/schema/migrations/,再执行mise //server:migrations sync-order,把它的名字(去掉.ts后缀)追加进 ORDER 清单。
ORDER 为什么必须和迁移一起提交?设想两个分支各自新增了一条迁移:如果只靠目录里的时间戳文件,合并后两条迁移会"静默"地以错误顺序执行——某条 DDL 依赖的表对方还没建,服务启动直接失败。ORDER 进了 git,两边各追加一行,合并必然冲突,逼着你显式定好先后顺序:这是用"冲突噪音"换"顺序确定性"。
自动应用与 CI 校验:重启即生效
开发环境不用手动执行迁移。服务端会监听.ts文件变化自动重启,而启动流程本身就包含"应用所有未执行的新迁移"这一步——保存文件、等它重启,迁移就落到本地库里了。
CI 侧,checklist 任务在单测和中测之后还会执行一次verify-order,确认磁盘上的迁移文件与 ORDER 清单一一对应,专门拦住"忘了 sync-order"这类提交。
Immich 迁移回滚与漂移排查
本地库状态和迁移历史对不上了怎么办?下面三个工具,从轻到重。
迁移回滚命令:revert 只回退一步
它只做一件事:执行最近一次已应用迁移的down(),把 schema 退回到迁移前。命令是mise //server:migrations revert,最适合用来验证你刚写的down逻辑是否真的可逆。注意它只回一步,不是批量撤销。
schema-check 漂移检测:三种状态判定
手工改过表、误删过迁移文件时,跑 schema-check 服务命令,核对"磁盘迁移"与"数据库实际状态"。每个迁移会被归入三种状态之一:applied(已应用)、deleted(数据库里已应用但磁盘文件没了)、missing(磁盘上有但还没应用)。
检测到漂移时,它会列出漂移项并附一段自动生成的修复 SQL。源码里明确标注了"Use at your own risk"——这段 SQL 仅供参考,执行前务必逐行人工确认。
本地数据库一键重建:drop 与 reset
最后一招是重建本地库。server/mise.toml里定义了两个任务:
[tasks."schema-drop"] run = { task = "migrations query 'DROP schema public cascade; CREATE schema public;'" } [tasks."schema-reset"] run = [ { task = ":schema-drop" }, { task = "migrations run" }, ]schema-drop先清空publicschema;schema-reset在此基础上按 ORDER 顺序重放全部 97 个迁移,得到一个与代码完全一致的干净库。⚠️警示:这两个操作仅限开发环境使用,会清空全部数据,严禁对生产库执行。
命令速查表:mise 任务与 npm scripts
| mise 任务(monorepo 根目录) | npm script(server 目录) | 作用 |
|---|---|---|
mise //server:migrations create <name> | migrations:create | 创建空迁移骨架 |
mise //server:migrations generate <name> | migrations:generate | 比对 schema 与数据库差异,自动生成迁移 DDL |
mise //server:migrations run | migrations:run | 执行所有未应用的迁移 |
mise //server:migrations revert | migrations:revert | 回滚最近一次迁移 |
mise //server:migrations sync-order | migrations:sync-order | 把新迁移登记进 ORDER 清单 |
mise //server:migrations verify-order | migrations:verify-order | 校验清单与磁盘文件一致(CI 使用) |
另有一个migrations:debug,等价于generate附带调试输出。
避坑清单:五个高频问题
- 生产环境禁用 drop / reset。
DROP SCHEMA public CASCADE会清掉全部业务数据,本文的"一键重建"只适用于本地开发库。 - 先确认
DB_URL可达。generate、run 类命令都会连真实数据库读取现状,连接串不通时,要么报错,要么比对出错误的差异。 - 工具版本以仓库锁文件为准。
@immich/sql-tools锁定在 0.6.3,自行全局装最新版再跑命令,生成的 DDL 可能和仓库对不上。 - ORDER 与迁移文件同一次提交。漏了
sync-order,verify-order会直接让 CI 变红;反过来只提交 ORDER 不提交文件同样不行。 - 空操作迁移文件别乱删。它维持着 ORDER 与磁盘文件的一一对应,删掉后数据库侧会把对应记录判成
deleted。
提交前:过一遍这五条
- 审读迁移的
up/down:DDL 符合预期、存量数据已回填、回退安全; - 迁移文件已移入
server/src/schema/migrations/; - 执行
sync-order,ORDER清单随本次提交一起提交; - 重启本地 server,确认迁移自动应用成功;
- 跑一遍
verify-order,通过后再推送。
【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考