首页 / 文章 / 在未运行 migrate reset 的情况下使用 Prisma 为现有数据库建立基线

在未运行 migrate reset 的情况下使用 Prisma 为现有数据库建立基线

了解为何 Prisma 会报告现有数据库出现偏移,为何“迁移重置”并非正确的解决方法,以及如何通过 db pull、migrate diff 和 migrate resolve 来建立基准。

1029 词

在已经包含表和数据的数据库上使用 Prisma Migrate 时,很可能会出现这样的情况:首次执行 npx prisma migrate dev 时会因结构不一致而触发警告,并提示重置所有内容。这个提示意味着数据库中存在迁移历史记录所不知道的结构。如果选择接受该建议,将会删除你的数据。本指南将解释为何会出现这种冲突、为什么对于重要的数据库来说几乎 never 应该选择重置,以及如何为现有架构建立基准,让 Prisma 将其视为起点并仅从该点开始应用变更。

为何 Prisma 会检测到冲突

Prisma Migrate 会保存两份关于模式演变的记录:一份是位于 prisma/migrations 目录中的迁移文件,另一份则是数据库中名为 _prisma_migrations 的表,用于记录哪些迁移文件已被应用。当运行 migrate dev 时,Prisma 会针对临时数据库重放迁移历史,并将结果与真实数据库进行比较。

如果真实数据库中存在某些迁移文件并未创建的表,比如是因为手动创建、由其他工具生成或来自应用程序的早期版本,那么这两个数据库就会不一致。Prisma 将这种情况称为“漂移”。由于 migrate dev 是一个开发命令,它的默认处理方式是清空数据库并根据迁移历史重新构建它,因此会建议进行重置。对于仅用于开发的本地数据库来说这很合理,但对于其他任何用途的数据库而言则具有破坏性。

如需了解阴影数据库如何参与此对比的更多背景信息,请参阅Prisma的阴影数据库与命名冲突问题。

为何migrate reset不是正确的解决方案

npx prisma migrate reset会删除数据库或其架构中的所有表,然后根据迁移文件重新创建它们并运行初始化脚本。所有现有数据都会丢失。对于包含真实用户、订单或内容的数据库而言,这并非冲突解决方式,而是数据丢失。

更好的方法是不要改动数据库,而是让Prisma对数据的认知与实际数据保持一致。具体做法是将当前结构记录为第一个迁移文件,并告知Prisma该迁移已存在。

逐步建立基准

步骤1:分析现有数据库

运行 npx prisma db pull。Prisma会连接到数据库,读取其中的表、列、索引及关联关系,并将对应的模型写入 schema.prisma 文件中。完成此步骤后,该架构文件就能准确描述数据库的当前状态。

步骤2:生成基准迁移文件但不立即应用

为基准版本创建一个文件夹,例如 prisma/migrations/0_init。0_ 前缀可确保该文件在后续按时间戳排序的迁移文件之前被处理。接着使用 npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql 生成用于从空状态构建当前数据结构的 SQL 语句并保存到该文件夹中。在较新版本的 Prisma 中,目标参数的名称可能改为 --to-schema,请根据您的版本查看 npx prisma migrate diff --help 的说明。

这一步很重要,因为它能在不修改数据库的情况下生成迁移文件。常见的错误是在此阶段运行 npx prisma migrate dev --name baseline。对于已经存在表且没有迁移历史的数据库,该命令会检测到与之前相同的差异并要求再次重置,而这正是你想要避免的。由于现有数据库中已经存在表,因此绝不能对它执行基准 SQL。

步骤 3:标记基准状态为已应用

运行 npx prisma migrate resolve --applied 0_init。该参数即为迁移文件夹的名称。如果文件夹是用时间戳命名的,例如 20250101120000_baseline,则必须使用完整的名称,而不仅仅是 baseline。

此命令不会对您的表执行任何 SQL 操作。它会在 _prisma_migrations 中插入一行,表明基准版本已应用。实际上您是在修改 Prisma 的记录机制,使其将当前结构视为有意且有效的。

此方法如何解决冲突

这类似于 Git 的合并冲突:当您的分支缺少主分支已有的提交时,您会更新分支而非删除主分支。此处数据库版本更新,因此需要让 Prisma 的历史记录与数据库保持一致。

基准版本记录之后,下一次执行 npx prisma migrate dev 时,会在影子数据库中重新运行 0_init,从而获得与真实数据库相同的结构,并检测到没有差异。此后,每当您修改 schema.prisma 时,Prisma 会生成仅包含差异的新迁移文件,并仅应用这些差异。

为何这对大型数据库至关重要

当数据库存储大量数据时,建立基线才能发挥最大作用。由于基线已记录在_prisma_migrations中,且架构与实际数据库一致,Prisma会保留现有的表和行,仅应用新的更改,这样你的users表就能保持完整。

请记住以下几点:

  • 针对每个现有环境(如测试环境和生产环境),各运行一次migrate resolve --applied,因为每个数据库都有独立的_prisma_migrations表。
  • 在生产环境中,应使用npx prisma migrate deploy来应用后续的迁移,而非仅适用于开发环境的migrate dev。
  • 将基线文件夹提交到版本控制系统中,以便所有开发人员和CI任务都能使用相同的起点。

核心要点

  • 现有数据库出现漂移警告意味着 Prisma 的迁移历史记录缺失,而非数据库本身有误。
  • 重置操作会删除数据;请将其视为仅适用于一次性本地数据库的工具。
  • 可通过 db pull 进行分析来确定基准,使用 migrate diff --from-empty 生成 SQL 语句,再通过 migrate resolve --applied 进行记录。
  • 切勿在已包含数据的数据库上使用 migrate dev 来创建基准,因为这会触发相同的重置提示。
  • 建立基准后,Prisma 仅管理增量变更,现有数据不会被修改。