
Immich 数据库迁移完整指南:从 schema 蓝图到一键回滚【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-PatcherImmich 的服务端表结构以 TypeScript 声明,任何对server/src/schema的改动,都要等一次迁移真正执行,才会注册进 PostgreSQL。这篇梳理 Immich 数据库迁移的完整路径:一条命令如何生成并审阅迁移文件、ORDER 清单为何必须随代码提交、服务重启时迁移如何自动生效,以及出错时 revert、schema-check、schema-reset 三条救援路径各自的适用场景。三层模型:蓝图、施工指令与施工台账理解这套机制前,先把 server/src/schema 拆成三层来看。目录由三部分构成:tables/:约 64 个表定义文件(如asset.table.ts、album.table.ts、plugin.table.ts),用immich/sql-tools的声明式 API 描述表结构,回答的是数据库应该长什么样;enums.ts 与 functions.ts:枚举、数据库函数与触发器定义;migrations/:按时间戳排序的迁移文件,外加一个 ORDER 清单文件。其中每个up()函数才是把已有数据库改成那样的实际执行单元。两层之间由迁移工具immich/sql-tools(workspace 中锁定为0.6.3,见pnpm-lock.yaml)桥接:它比对声明式 schema 与真实数据库的差异,自动生成迁移 SQL,并在启动或测试时按 ORDER 清单顺序执行。这样做的好处是蓝图可以随便重构,数据库只跟着施工指令变。对照着看:层对应产物职责蓝图tables/、enums、functions描述目标状态,本身不改数据库施工指令migrations/*.tsup()/down()是执行单元施工台账migrations/ORDER决定执行顺序,受 git 管理ORDER 清单可以理解成一本施工台账:哪条指令、按什么顺序执行,逐行在册。为什么这本台账必须进版本控制,下文单独讲。如何一条命令生成迁移文件先说目的:让工具把蓝图和本地数据库做比对,自动吐出 DDL,而不是手写 SQL。# 在 monorepo 根目录执行 mise //server:migrations generate migration-name//server:前缀表示从仓库根目录执行server包的任务(mise.toml声明了monorepo_root true)。该任务在 server/mise.toml 中定义为sql-tools -u ${DB_URL:-postgres://postgres:postgreslocalhost:5432/immich} migrations,generate等子命令只是追加到末尾。两点要注意:DB_URL指向目标数据库,未设置时默认连localhost:5432/immich,即本地 Docker 开发环境里的 Postgres——数据库不可达,生成这一步就进行不下去;产物以毫秒时间戳 PascalCase命名,形如1745244781846-AddUserAvatarColorColumn.ts,而且不直接落在最终目录,需要手动移入 server/src/schema/migrations。该目录当前共有 97 个迁移文件,从1744910873969-InitialMigration.ts(初始迁移)排到最新的1787148183730-DeleteMismatchedMemoryAssets.ts。时间戳前缀保证了同目录内字典序即执行顺序——这也是命名规范不能随意破坏的原因。如何读懂迁移文件里的 up 与 down每个迁移文件导出up()与down()两个异步函数,内部用 kysely 的sql标签模板执行原生 SQL。以真实迁移1745244781846-AddUserAvatarColorColumn.ts为例:import { Kysely, sql } from kysely; export async function up(db: Kyselyany): Promisevoid { await sqlALTER TABLE users ADD avatarColor character varying;.execute(db); await sql UPDATE users SET avatarColor user_metadata.value-avatar-color FROM user_metadata WHERE users.id user_metadata.userId AND user_metadata.key preferences;.execute(db); } export async function down(db: Kyselyany): Promisevoid { await sqlALTER TABLE users DROP COLUMN avatarColor;.execute(db); }读法:up先加列,再关联 JSON 元数据表把存量用户的数据回填进新列;down只负责把列删回去。人工审阅时盯三件事——生成的 DDL 是否符合预期、down能否安全回退、有没有遗漏数据回填。还有一类特例:部分迁移的up/down都是空操作(如1750323941566-UnsetPrewarmDimParameter.ts)。这类占位文件的意义仅在于维持 ORDER 清单与磁盘文件的一一对应,审阅时别当成可以删的冗余。ORDER 清单为什么必须随代码提交迁移文件审阅通过后,把它登记进清单:执行mise //server:migrations sync-order,新迁移会被追加到 server/src/schema/migrations/ORDER,每行一个文件名(去掉.ts后缀):1744910873969-InitialMigration 1744991379464-AddNotificationsTable 1745244781846-AddUserAvatarColorColumn为什么要强制提交这本台账?因为它受 git 跟踪。两个分支各自新增迁移时,一定会在这个文件上产生合并冲突,逼着开发者显式决定谁先谁后;如果只依赖目录里的时间戳文件,两个分支会静默地以错误顺序合并——谁先执行,谁的 DDL 就可能引用尚不存在的表,最后表现为服务启动失败。设计上的取舍很清楚:代价是偶尔要手工解冲突,收益是顺序问题在提交时就暴露,而不是在运行时才炸。CI 侧也堵住了漏提交的口子:server/mise.toml 的checklist任务在单测与中测之后还会跑{ task :migrations, args [verify-order] }。verify-order校验磁盘上的迁移文件与 ORDER 清单完全一致,专门防的就是忘了跑sync-order。服务重启后,迁移如何自动生效开发环境的服务端会监听*.ts文件变更并自动重启,而启动流程本身就包含运行所有未应用的迁移这一环节。所以在开发环境里重启或重载 server,新迁移会立即落到本地数据库,不需要手动执行run。这样做的好处是省掉独立执行环节;代价是数据库状态与代码强绑定——清单完整时,重启就等于应用到最新。反过来,这也意味着清单一旦漏了条目,问题会一直潜伏到下次启动。出错时怎么办:回滚、漂移检测与本地重建出错后按场景选工具,三种救援各管一段。回滚最近一次迁移。执行mise //server:migrations revert,它会跑最新一条迁移的down(),把数据库恢复到迁移前状态。最典型的用途是验证自己写的down逻辑是否真的可逆。漂移检测。schema-check服务命令(实现在 server/src/commands/schema-check.ts)核对磁盘迁移与数据库实际状态是否一致,把每个迁移归为三种状态:applied:已应用,正常路径;deleted:数据库里已应用,但磁盘上文件不见了;missing:磁盘上存在,但尚未应用到数据库。检测到漂移时,命令会列出漂移项(用immich/sql-tools的asHuman渲染),并附一段自动生成的修复 SQL。源码里明确标注 Use at your own risk!——这段 SQL 仅供参考,执行前必须人工确认。本地一键重建。server/mise.toml 还定义了schema-drop与schema-reset两个本地重建任务:先DROP SCHEMA public CASCADE重建空的 public schema,再migrations run按 ORDER 清单顺序重放全部 97 个迁移,得到与代码完全一致的干净数据库。当本地库与迁移历史对不上(手工改过表、误删过迁移文件)导致schema-check报错时,这是最可靠的恢复手段。⚠️ 两个操作都会清空数据,仅限本地开发库使用,生产环境切勿照搬。两套命令等价,按习惯二选一:操作mise(仓库根目录执行)npm 脚本(server 目录内执行)创建空迁移骨架mise //server:migrations createmigrations:create比对 schema 自动生成 DDLmise //server:migrations generate namemigrations:generate同 generate,带调试输出—migrations:debug执行所有未应用的迁移mise //server:migrations runmigrations:run回滚最近一次迁移mise //server:migrations revertmigrations:revert将新迁移登记进 ORDERmise //server:migrations sync-ordermigrations:sync-order校验清单与文件一致性(CI 使用)mise //server:migrations verify-ordermigrations:verify-order提交变更前的自检清单tables/ 等声明式定义改完,generate产出的迁移已人工过审:DDL 无误、down可回退、存量数据回填未遗漏;迁移文件已移入server/src/schema/migrations,sync-order已执行,ORDER 清单随代码一并提交;本地 Postgres 可达(默认DB_URL指向localhost:5432/immich);重启 server 后迁移自动应用,schema-check报告无漂移;必要时用revert实际演练一遍回滚,确认down逻辑生效;verify-order通过——CI 的 checklist 同样会执行它。【免费下载链接】OpenCore-Legacy-PatcherExperience macOS just like before项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考