架构与迁移
如何在开发、CI 和生产环境中安全地演进 Prisma 架构并运行数据库迁移。
Prisma 架构是数据库结构的唯一事实来源。对表、列、索引和关系的所有更改都通过 packages/platform/db/prisma/schema.prisma 进行。迁移是由 Prisma 生成的版本化 SQL 文件,与架构一起存储。
文件位置
packages/platform/db/
prisma/
schema.prisma ← 编辑此文件以更改数据模型
migrations/ ← 生成的迁移文件(提交这些文件)
20240101000000_init/
migration.sql
20240215120000_add_projects/
migration.sql
seed.ts ← 开发种子数据prisma/migrations/ 中的迁移文件是每次架构更改的权威记录。始终将它们提交到版本控制 — 这是生产数据库保持同步的方式。
开发工作流
打开 packages/platform/db/prisma/schema.prisma 并进行更改 — 添加模型、添加列、创建索引等。
model Project {
id String @id @default(cuid())
name String
slug String @unique
description String?
tenantId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([tenantId])
@@map("projects")
}编辑架构后,重新生成 TypeScript 客户端,使应用程序代码立即反映新类型。
pnpm db:generate这将运行 prisma generate 并更新 node_modules/@prisma/client 中的类型。无需重启开发服务器 — Next.js 会在下一个请求时获取新类型。
用一条命令创建命名迁移文件并将其应用到本地数据库:
pnpm db:migratePrisma 将提示输入迁移名称(例如 add_project_model),然后:
- 对比当前架构与上次迁移状态
- 在
prisma/migrations/中生成migration.sql文件 - 将 SQL 应用到本地数据库
生成的迁移文件必须与架构更改一起提交。这是 CI/CD 和生产数据库接收更新的方式。
git add packages/platform/db/prisma/
git commit -m "feat(db): add Project model"push 与 migrate 的区别
pnpm db:push 直接将架构同步到数据库,不创建迁移文件。仅用于尚不需要迁移历史记录的本地快速原型开发。
pnpm db:push使用时机:
- 对新模型的早期探索
- 一次性本地数据库
- 在准备好编写正式迁移之前的迭代
db:push 不创建迁移文件。通过此方式应用的更改无法在其他环境中重放。永远不要在共享、预发布或生产数据库上使用它。
pnpm db:migrate 创建版本化迁移文件并应用它。这是除一次性本地数据库之外所有环境的正确工作流。
pnpm db:migrate使用时机:
- 在开发中添加或删除模型
- 需要到达预发布或生产环境的任何更改
- 团队环境中的所有更改
迁移名称嵌入在目录名称中,并用于审计日志。
CI/CD:在部署前运行迁移
迁移必须在部署新应用程序代码之前应用到数据库。在流水线中添加此步骤:
- name: 运行数据库迁移
run: pnpm db:migrate
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
DIRECT_URL: ${{ secrets.DIRECT_URL }}运行迁移时,Prisma 需要 DIRECT_URL(直接、非连接池连接)。PgBouncer 和 Supavisor 等连接池不支持 Prisma 在迁移期间使用的 DDL 语句。在 CI 密钥和 schema.prisma 中设置 DIRECT_URL:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}零停机滚动迁移
对于影响大型表的生产更改,使用扩展-收缩模式以避免在部署期间锁定行:
model User {
// 现有字段 ...
displayName String? // ← 可空;旧代码忽略它,新代码写入它
}部署此迁移。新旧两个应用程序版本都可以安全运行。
运行后台任务或一次性脚本为所有现有用户填充 displayName。保持批量处理以避免长时间运行的事务。
一旦所有行都已回填,且只有新版本的应用程序在运行,应用第二个迁移来添加 NOT NULL 约束。
model User {
displayName String // ← 现在必填
}回滚迁移
Prisma 不提供自动回滚。要回滚迁移:
创建一个撤销更改的新迁移 — 删除添加的列、重新创建删除的表等。
pnpm db:migrate
# 命名为:revert_add_display_name如果仍在开发阶段且迁移尚未到达生产环境,可以删除迁移目录并重置本地数据库:
# 删除不需要的迁移目录
rm -rf packages/platform/db/prisma/migrations/20240215_add_display_name
# 将本地数据库重置到上一个良好迁移状态
pnpm --filter @nebutra/db exec prisma migrate resetprisma migrate reset 会删除并重新创建整个本地数据库。永远不要在共享或生产数据库上运行它。
pgvector 设置
recsys 架构使用 pgvector 扩展。在初始迁移运行之前,数据库必须启用该扩展。
pgvector 预安装在所有 Neon 数据库上。无需操作。
pgvector 作为托管扩展提供。从 Supabase 控制台的数据库 → 扩展中启用,或通过 SQL 启用:
CREATE EXTENSION IF NOT EXISTS vector;在 PostgreSQL 服务器上安装扩展,然后在数据库中启用它:
# Debian/Ubuntu
sudo apt install postgresql-16-pgvector
# macOS (Homebrew)
brew install pgvectorCREATE EXTENSION IF NOT EXISTS vector;如果在首次运行 pnpm db:migrate 之前未安装 pgvector,第一次迁移将因 extension "vector" does not exist 而失败。
How is this guide?
最后更新于