Skip to content
On this page

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 不直接支持回滚
# 需要创建反向迁移

手动回滚

如果需要回滚:

  1. 手动编写反向 SQL
  2. 创建新的迁移来撤销更改
  3. 或者使用数据库特定的回滚工具
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 和数据库同步

通过遵循这些迁移实践,您可以安全、可靠地管理数据库架构的演进,确保应用程序的稳定性和数据完整性。