Immich 数据库迁移实战:从加一列到一键回滚
2026/9/10 18:45:53 网站建设 项目流程

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.tsfunctions.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 runmigrations:run执行所有未应用的迁移
mise //server:migrations revertmigrations:revert回滚最近一次迁移
mise //server:migrations sync-ordermigrations:sync-order把新迁移登记进 ORDER 清单
mise //server:migrations verify-ordermigrations: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-orderverify-order会直接让 CI 变红;反过来只提交 ORDER 不提交文件同样不行。
  • 空操作迁移文件别乱删。它维持着 ORDER 与磁盘文件的一一对应,删掉后数据库侧会把对应记录判成deleted

提交前:过一遍这五条

  1. 审读迁移的up/down:DDL 符合预期、存量数据已回填、回退安全;
  2. 迁移文件已移入server/src/schema/migrations/
  3. 执行sync-orderORDER清单随本次提交一起提交;
  4. 重启本地 server,确认迁移自动应用成功;
  5. 跑一遍verify-order,通过后再推送。

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

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

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

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

立即咨询