Appearance
Prisma Migrations
Prisma Migrate 是一个声明式的数据库迁移系统,允许您安全地演进数据库架构。本指南将详细介绍如何使用 Prisma Migrate 来管理和应用数据库迁移。
什么是数据库迁移
数据库迁移是管理数据库架构变更的过程。它允许您:
- 安全地添加、修改或删除数据库表和字段
- 保持团队间的数据库架构同步
- 回滚到之前的数据库状态
- 在不同环境间同步数据库架构
基本迁移工作流
1. 初始化迁移
首次设置数据库迁移:
bash
# 初始化第一个迁移
npx prisma migrate dev --name init
这将:
- 根据 schema.prisma 文件创建数据库架构
- 在 prisma/migrations 目录下生成迁移文件
- 更新 Prisma 状态以反映当前数据库架构
2. 创建新迁移
当您修改 schema.prisma 文件后:
bash
# 创建新的迁移
npx prisma migrate dev --name add-user-profile
迁移命令详解
开发环境迁移
bash
# 创建并应用迁移(开发环境)
npx prisma migrate dev --name migration-name
# 创建迁移但不应用(仅生成 SQL 文件)
npx prisma migrate diff \
--from-empty \
--to-schema-datamodel prisma/schema.prisma \
--script > migration.sql
# 检查迁移状态
npx prisma migrate status
# 重置数据库(删除所有数据并重新应用所有迁移)
npx prisma migrate reset
生产环境迁移
bash
# 应用待处理的迁移(生产环境)
npx prisma migrate deploy
# 检查待应用的迁移
npx prisma migrate status
迁移文件结构
迁移文件位于 prisma/migrations/ 目录下:
prisma/migrations/
├── 20230101120000_init/
│ └── migration.sql
├── 20230102143000_add_user_profile/
│ └── migration.sql
└── 20230103101500_add_posts_table/
└── migration.sql
每个迁移目录包含:
migration.sql: 实际的 SQL 语句- 迁移名称基于时间戳和描述
实际迁移示例
初始架构迁移
首先定义初始 schema:
prisma
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
创建初始迁移:
bash
npx prisma migrate dev --name init
添加新字段
修改 schema 以添加新字段:
prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
bio String? // 新增字段
posts Post[]
createdAt DateTime @default(now()) // 新增字段
updatedAt DateTime @updatedAt // 新增字段
}
创建迁移:
bash
npx prisma migrate dev --name add-user-bio-and-timestamps
添加新表
添加新的数据模型:
prisma
model Category {
id Int @id @default(autoincrement())
name String @unique
slug String @unique
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
category Category? @relation(fields: [categoryId], references: [id])
categoryId Int?
createdAt DateTime @default(now())
}
创建迁移:
bash
npx prisma migrate dev --name add-category-table
高级迁移场景
重命名字段或表
Prisma 不直接支持重命名,需要手动编写迁移:
prisma
// schema.prisma - 重命名前
model User {
id Int @id @default(autoincrement())
email String @unique
fname String // 要重命名的字段
}
prisma
// schema.prisma - 重命名后
model User {
id Int @id @default(autoincrement())
email String @unique
firstName String @map("fname") // 使用 @map 保持数据库列名
}
或者创建手动迁移:
sql
-- prisma/migrations/xxxxxx_rename_column/migration.sql
ALTER TABLE "User" RENAME COLUMN "fname" TO "firstName";
数据迁移
有时需要在架构更改的同时迁移数据:
bash
# 创建空迁移用于数据迁移
npx prisma migrate dev --name migrate-user-data
然后编辑生成的迁移文件:
sql
-- prisma/migrations/xxxxxx_migrate-user-data/migration.sql
-- 添加新字段
ALTER TABLE "User" ADD COLUMN "fullName" TEXT;
-- 迁移数据
UPDATE "User" SET "fullName" = CONCAT("firstName", ' ', "lastName");
-- 删除旧字段(如果需要)
-- 注意:在不同数据库中有不同的语法
复杂架构更改
对于复杂的架构更改,可以使用原生 SQL:
prisma
model Product {
id Int @id @default(autoincrement())
name String
description String?
price Decimal
currency String @default("USD") // 新增字段
tags String[] @default([]) // 新增字段
}
创建迁移:
bash
npx prisma migrate dev --name add-product-fields
迁移最佳实践
1. 在开发分支上测试迁移
bash
# 在功能分支上创建迁移
git checkout feature/new-feature
npx prisma migrate dev --name add-feature-table
# 测试迁移
npm test
# 合并到主分支前验证
git checkout main
git merge feature/new-feature
npx prisma migrate dev --name add-feature-table # 应该已经应用过了
2. 使用迁移检查器
bash
# 检查 schema 和数据库是否同步
npx prisma db pull
# 比较 schema 和数据库
npx prisma migrate diff \
--from-schema-datamodel prisma/schema.prisma \
--to-url "$DATABASE_URL"
3. 生产环境安全措施
bash
# 1. 在暂存环境测试迁移
npx prisma migrate deploy --schema prisma/schema.prisma
# 2. 检查待应用的迁移
npx prisma migrate status
# 3. 备份数据库
pg_dump mydb > backup.sql # 示例 PostgreSQL 备份
# 4. 应用迁移
npx prisma migrate deploy
处理迁移冲突
当多人同时修改 schema 时
bash
# 如果遇到迁移冲突
npx prisma migrate resolve --applied migration-name # 如果迁移已手动应用
# 或者重置并重新应用
npx prisma migrate reset
手动解决迁移问题
bash
# 检查迁移历史
npx prisma migrate status
# 如果迁移失败,可以:
# 1. 修复 schema.prisma
# 2. 删除失败的迁移文件夹
# 3. 重新创建迁移
预生产验证
验证迁移在镜像环境中的效果
bash
# 使用影子数据库验证迁移(某些数据库支持)
npx prisma migrate dev --name test-migration --create-only
# 然后手动检查生成的 SQL
CI/CD 集成
yaml
# .github/workflows/deploy.yml 示例
name: Deploy
on:
push:
branches: [main]
jobs:
migrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npx prisma generate
# 验证迁移是否可以应用
- run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
回滚和恢复
查看迁移历史
bash
# 查看迁移历史
npx prisma migrate status
# 注意:Prisma Migrate 不直接支持回滚
# 需要创建反向迁移
手动回滚
如果需要回滚:
- 手动编写反向 SQL
- 创建新的迁移来撤销更改
- 或者使用数据库特定的回滚工具
sql
-- 示例:撤销添加字段的迁移
ALTER TABLE "User" DROP COLUMN "bio";
故障排除
常见迁移错误
bash
# 如果出现 "Database schema is not synchronized with your Prisma schema" 错误
npx prisma db pull # 拉取当前数据库架构
# 如果迁移状态混乱
npx prisma migrate reset # 重置并重新开始(会丢失数据)
# 检查数据库连接
npx prisma db pull --force # 强制拉取
验证迁移完整性
bash
# 验证 schema 和数据库的一致性
npx prisma migrate diff \
--from-url "$DATABASE_URL" \
--to-schema-datamodel prisma/schema.prisma
# 如果输出为空,则 schema 和数据库同步
通过遵循这些迁移实践,您可以安全、可靠地管理数据库架构的演进,确保应用程序的稳定性和数据完整性。