跳至主要内容

修补和热修复

修补或热修复数据库涉及在生产环境中直接进行一项通常很关键的更改。例如,您可能直接在生产数据库中添加索引以解决慢速运行查询的问题。

直接修补生产数据库会导致 **模式漂移**:您的数据库模式已“偏离”真相来源,并且与您的迁移历史记录不同步。您可以使用 prisma migrate resolve 命令协调您的迁移历史记录, *无需* 使用 prisma migrate deploy 删除并重新应用热修复。

警告

本指南 **不适用于 MongoDB**。
不是 migrate devdb push 用于 MongoDB

协调您的迁移历史记录和修补程序或热修复程序

以下场景假设您在生产环境中进行了手动更改,并希望将该更改传播到您的迁移历史记录和其他数据库。

要协调生产环境中的迁移历史记录和数据库模式

  1. 在模式中复制您在生产环境中所做的更改 - 例如,将 @@index 添加到特定模型。

  2. 生成新的迁移并记下完整的迁移名称,包括时间戳,该时间戳会写入 CLI:(20210316150542_retroactively_add_index

    npx prisma migrate dev --name retroactively-add-index
    显示CLI结果
    migrations/
    └─ 20210316150542_retroactively_add_index/
    └─ migration.sql

    Your database is now in sync with your schema.

    ✔ Generated Prisma Client (2.19.0-dev.29) to .\node_modules\@prisma\client in 190ms
  3. 将迁移推送到生产环境 **而不运行 migrate deploy**。相反,将上一步中创建的迁移标记为“已应用”,这样 Prisma Migrate 就不会尝试第二次应用您的热修复。

    prisma migrate resolve --applied "20201127134938-retroactively-add-index"

    此命令将迁移添加到迁移历史记录表中,而不运行实际的 SQL。

  4. 对其他已修补的数据库重复上一步 - 例如,如果您将修补程序应用于暂存数据库。

  5. 将迁移传播到未修补的其他数据库 - 例如,通过将迁移提交到源代码控制并允许您的 CI/CD 管道将其应用于所有数据库。

**注意**:迁移不会应用于已通过 prisma migrate resolve 命令标记为已应用的数据库。

迁移失败

如果以下情况发生,迁移可能会失败

  • 在运行迁移之前修改了迁移 并引入了语法错误
  • 您向已包含数据的表添加了必填 (NOT NULL) 列
  • 迁移过程意外停止
  • 数据库在迁移过程的中间关闭

_prisma_migrations 表中的每个迁移都包含一个 logs 列,用于存储错误。

有两种方法可以处理生产环境中的迁移失败

  • 回滚,可选地修复问题,然后重新部署
  • 手动完成迁移步骤并解决迁移

选项 1:将迁移标记为回滚并重新部署

以下示例演示了如何回滚迁移,可选地进行更改以修复问题,然后重新部署

  1. 将迁移标记为回滚 - 这会更新 _prisma_migrations 表中的迁移记录以将其注册为回滚,从而允许再次应用它

    prisma migrate resolve --rolled-back "20201127134938_added_bio_index"
  2. 如果迁移已部分运行,您可以

    • 修改迁移以检查步骤是否已完成(例如:CREATE TABLE ... IF NOT EXISTS) *或*

    • 手动撤消已完成的步骤(例如,删除已创建的表)

    如果修改了迁移,请确保将其复制回源代码控制,以确保生产数据库的状态与开发中的状态完全一致。

  3. 修复迁移失败的根本原因(如果相关) - 例如,如果迁移由于 SQL 脚本本身的问题而失败。确保将任何更改的迁移复制回源代码控制。

  4. 重新部署迁移

    prisma migrate deploy

选项 2:手动完成迁移并将其解决为应用

以下示例演示了如何手动完成迁移步骤并将该迁移标记为已应用。

  1. 手动完成生产数据库上的迁移步骤。确保任何手动步骤与迁移文件中的步骤完全匹配,并将任何更改复制回源代码控制。

  2. 将迁移解决为已应用 - 这会告诉 Prisma Migrate 将迁移视为已成功应用

    prisma migrate resolve --applied "20201127134938_my_migration"

使用 migrate diffdb execute 修复迁移失败

为了帮助修复迁移失败,Prisma ORM 提供了以下命令,用于创建和执行迁移文件

  • prisma migrate diff 用于对两个数据库模式源进行差异化,以创建迁移,将一个迁移到第二个状态。您可以输出差异的摘要或 SQL 脚本。可以通过 > file_name.sql 将脚本输出到文件,或者将其管道传输到 db execute --stdin 命令。
  • prisma db execute 用于将 SQL 脚本应用于数据库,而不与 Prisma 迁移表进行交互。

这些命令在 3.9.0 及更高版本(使用 --preview-feature CLI 标志)中处于预览阶段,并且在 3.13.0 及更高版本中普遍可用。

本节提供了一个迁移失败的示例场景,并解释了如何使用 migrate diffdb execute 来修复它。

迁移失败的示例

假设您在模式中具有以下 User 模型,在您的本地开发环境和生产环境中均如此

schema.prisma
model User {
id Int @id
name String
}

此时,您的模式已同步,但两个环境中的数据不同。

然后,您决定对数据模型进行更改,添加另一个 Post 模型并将 User 上的 name 字段设为唯一

schema.prisma
model User {
id Int @id
name String @unique
email String?
}

model Post {
id Int @id
title String
}

您使用命令 prisma migrate dev -n Unique 创建了一个名为“Unique”的迁移,该迁移保存在您的本地迁移历史记录中。应用迁移在您的开发环境中成功,现在是时候发布到生产环境了。

不幸的是,此迁移只能部分执行。创建 Post 模型和添加 email 列成功,但将 name 字段设为唯一失败,并显示以下错误

ERROR 1062 (23000): Duplicate entry 'paul' for key 'User_name_key'

这是因为生产数据库中存在非唯一数据(例如,两个具有相同名称的用户)。

现在,您需要从部分执行的迁移中手动恢复。在您从失败状态恢复之前,无法使用 prisma migrate deploy 进行进一步的迁移。

此时,您有两个选择,具体取决于您对非唯一数据要做什么

  • 您意识到非唯一数据是有效的,并且您无法继续进行当前的开发工作。您希望回滚完整的迁移。要执行此操作,请参阅 向后移动并撤消所有更改
  • 数据库中存在非唯一数据是无意的,并且您想修复它。修复后,您想继续进行迁移的其余部分。要执行此操作,请参阅 向前移动并应用缺少的更改

向后移动并撤消所有更改

在这种情况下,您需要创建一个迁移,将您的生产数据库迁移到上次迁移之前的数据模型状态。

  • 首先,您需要在上次迁移失败之前的时间点获取迁移历史记录。您可以从您的 Git 历史记录中获取它,或者在本地删除本地迁移历史记录中上次失败迁移的文件夹。

  • 现在,您想将生产环境从其当前失败状态迁移回本地迁移历史记录中指定的状态

    • 运行以下 prisma migrate diff 命令

       npx prisma migrate diff \
      --from-url "$DATABASE_URL_PROD" \
      --to-migrations ./prisma/migrations \
      --shadow-database-url $SHADOW_DATABASE_URL \
      --script > backward.sql

      这将创建一个 SQL 脚本文件,其中包含将您的生产环境从当前故障状态迁移到您的迁移历史记录定义的目标状态所需的所有更改。请注意,由于我们使用的是--to-migrations,因此该命令需要一个影子数据库

    • 运行以下prisma db execute 命令

       npx prisma db execute --url "$DATABASE_URL_PROD" --file backward.sql

      这将在目标数据库上应用 SQL 脚本中的更改,而不会与迁移表交互。

    • 运行以下prisma migrate resolve 命令

       npx prisma migrate resolve --rolled-back Unique

      这将在您的生产环境上的迁移表中将名为“Unique”的失败迁移标记为回滚。

您本地的迁移历史记录现在将与您的生产数据库的状态产生相同的结果。现在,您可以再次修改数据模型,以创建一个适合您对正在处理的功能的新理解的迁移(使用非唯一名称)。

向前移动并应用缺失的更改

在这种情况下,您需要修复非唯一数据,然后继续按照计划进行其余迁移。

  • 尝试将迁移部署到生产环境的错误消息已经告诉您,name列中存在重复数据。您需要更改或删除有问题的行。

  • 继续应用其余失败的迁移,以到达schema.prisma文件中定义的数据模型。

    • 运行以下 prisma migrate diff 命令


      npx prisma migrate diff --from-url "$DATABASE_URL_PROD" --to-schema-datamodel schema.prisma --script > forward.sql

      这将创建一个 SQL 脚本文件,其中包含将您的生产环境从当前故障状态迁移到schema.prisma文件中定义的目标状态所需的所有更改。

    • 运行以下prisma db execute 命令

      npx prisma db execute --url "$DATABASE_URL_PROD" --file forward.sql

      这将在目标数据库上应用 SQL 脚本中的更改,而不会与迁移表交互。

    • 运行以下prisma migrate resolve 命令

      npx prisma migrate resolve --applied Unique

      这将在您的生产环境上的迁移表中将名为“Unique”的失败迁移标记为已应用。

您本地的迁移历史记录现在将与您的生产环境的状态产生相同的结果。现在,您可以继续使用已知的migrate dev /migrate deploy 工作流程。

迁移历史冲突

info

这从版本3.12.0 开始不再适用。

prisma migrate deploy 会发出警告,提示已应用的迁移已被编辑 - 但是,它不会停止迁移过程。要删除警告,请从源代码管理中还原原始迁移。

Prisma Migrate 和 PgBouncer

如果您尝试在使用 PgBouncer 进行连接池的环境中运行 Prisma Migrate 命令,可能会看到以下错误。

Error: undefined: Database error
Error querying the database: db error: ERROR: prepared statement "s0" already exists

有关更多信息和解决方法,请参见Prisma Migrate 和 PgBouncer 的解决方法。有关更新,请关注GitHub 问题 #6485