Prisma迁移历史与数据库状态不一致问题排查与解决

1266 字
6 分钟
Prisma迁移历史与数据库状态不一致问题排查与解决

Prisma迁移历史与数据库状态不一致问题排查与解决#

核心问题#

Prisma 迁移历史与数据库实际状态不一致,导致 prisma migrate dev 无法正常执行。


问题链路(逐步暴露)#

1. 重复迁移文件#

现象:20260111065200_add_file_hash 和 20260111065014 两个迁移都添加了 fileHash 列,影子数据库执行时报 column already exists。

原因:开发过程中多次生成了添加同一字段的迁移。

解决:将 fileHash 合并到 init 迁移,删除两个重复迁移文件夹。


2. 修改已执行的迁移导致 checksum 不匹配#

现象:The migration was modified after it was applied

原因:修改了 init 迁移的 SQL 内容,但数据库 _prisma_migrations 表记录的 checksum 还是旧的。

解决:用 sha256sum 计算新文件 checksum,手动 UPDATE _prisma_migrations SET checksum = '...'。


3. 删除的迁移仍在数据库记录中#

现象:missing from the local migrations directory

原因:本地删除了迁移文件夹,但 _prisma_migrations 表还记录着它们已执行。

解决:清空 _prisma_migrations 表,重新标记。


4. 数据库结构与 schema.prisma 存在 drift#

现象:大量索引重命名(_index vs _idx)、关联表约束差异(unique index vs primary key)、外键差异。

原因:之前可能用过 prisma db push 直接同步数据库,db push 生成的数据库结构和 migrate dev 生成的有细微差异(索引命名规则不同)。

解决:

Terminal window
# 1. 用 migrate diff 找出精确差异(从数据库实际状态 → schema.prisma 期望状态,输出的 SQL 就是需要在数据库上执行的修复脚本)
npx prisma migrate diff --from-schema-datasource prisma/schema.prisma --to-schema-datamodel prisma/schema.prisma --script
# 2. 手动执行 SQL 对齐数据库(分三批:约束修复、外键重建、索引重命名)
npx prisma db execute --stdin --schema prisma/schema.prisma < fix.sql
# 3. 验证差异为空
npx prisma migrate diff --from-schema-datasource prisma/schema.prisma --to-schema-datamodel prisma/schema.prisma --script
# 输出: "This is an empty migration."

5. Advisory Lock 超时#

现象:Timed out trying to acquire a postgres advisory lock

原因:之前多次执行 Prisma 命令,某些连接未正常释放数据库锁。

解决:重启数据库服务释放所有连接。


最终方案总结#

步骤操作
1删除所有旧迁移文件夹
2手动执行 SQL 对齐数据库结构与 schema.prisma
3migrate diff --from-empty --to-schema-datamodel 生成新的 init 迁移
4migrate resolve --applied 标记为已执行
5如果中途修改过迁移文件,需手动更新 _prisma_migrations 表的 checksum

经验教训#

  1. **不要混用 db push 和 migrate dev**:两者生成的数据库结构有细微差异(索引命名等),混用会导致 drift
  2. 不要随意修改已执行的迁移文件:Prisma 用 checksum 校验,修改后必须同步更新
  3. 不要随意删除迁移文件夹:需同步清理 _prisma_migrations 表记录
  4. **migrate diff 是排查利器**:可以精确对比 schema、数据库、迁移文件之间的差异

数据库迁移方案#

未来如需将数据库迁移到新服务器,可以使用 Navicat 等工具导出导入。

关键点:prisma migrate dev 执行时会做三重校验:

  1. _prisma_migrations 表记录 ↔ 本地迁移文件(是否匹配、checksum 是否一致)
  2. 迁移文件执行结果 ↔ 影子数据库(迁移能否在空库上干净重放)
  3. 迁移文件重放后的预期结构 ↔ 数据库实际结构(是否存在 drift)

本轮对话遇到的问题就是:即使 _prisma_migrations 数据完整迁移过来了,但迁移文件有重复、被修改、被删除,或数据库结构与迁移预期有偏差(如之前用过 db push),仍然会导致校验失败。所以仅靠导出 _prisma_migrations 表并不能保证迁移正常。

推荐方案:Prisma 建表 + Navicat 只导数据#

这是最稳妥的方式,由 Prisma 完全掌控表结构和迁移记录,避免任何不一致。

Terminal window
# 1. 修改 .env 指向新数据库
# DATABASE_URL="postgresql://user:password@new-host:5432/mo_gallery"
# 2. 让 Prisma 在新库创建表结构 + _prisma_migrations 记录(自动执行所有迁移)
npx prisma migrate deploy
# 3. 用 Navicat 从旧库只导出业务数据(不含表结构,不含 _prisma_migrations 表),导入新库
# 注意:导入时选择「追加数据」而非「覆盖」,避免清空 _prisma_migrations 表
# 4. 验证
npx prisma migrate status
# 输出: Database schema is up to date!

为什么不推荐 Navicat 全量导出(含表结构 + _prisma_migrations):

本轮对话的问题就是前车之鉴。如果旧库本身存在以下问题,全量导出会把隐患一起带到新库:

  • 旧库用过 db push,表结构与迁移预期存在 drift(索引命名、约束类型等差异)
  • _prisma_migrations 中的 checksum 与修改过的迁移文件不匹配
  • 已删除的迁移记录残留在表中

注意:如果旧库状态已经完全正确(prisma migrate status 显示 up to date 且无 drift),全量导出也是可行的。关键是确保旧库本身没有历史遗留问题。

而由 Prisma 执行 migrate deploy 建表,能保证三者完全一致:

  • 表结构 = schema.prisma 定义
  • _prisma_migrations = 迁移文件的忠实记录
  • checksum = 当前迁移文件的真实校验值

 

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Prisma迁移历史与数据库状态不一致问题排查与解决
https://shaio.top/posts/丫丫学语/golang/prisma迁移历史与数据库状态不一致问题排查与解决/
作者
沙海
发布于
2026-06-17
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
沙海
Hello, I'm Shai.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
84
分类
15
标签
48
总字数
67,035
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
GitHub Actions
博客版本
Firefly v6.12.2
文章许可
CC BY-NC-SA 4.0

文章目录