{T}

Prisma数据库同步与迁移命令详解

Prisma数据库同步与迁移命令详解

学习目标:掌握 prisma db pull、prisma db seed、prisma db execute 等数据库操作命令,理解数据库同步和迁移的最佳实践。


一、Prisma 数据库命令概览

1.1 数据库相关命令一览

code
Prisma 数据库命令概览:
│
├── prisma db pull
│   ├── 作用:从数据库同步 Schema
│   ├── 场景:已有数据库,生成 Prisma Schema
│   └── 方向:Database → Schema
│
├── prisma db push
│   ├── 作用:将 Schema 同步到数据库
│   ├── 场景:原型开发、快速迭代
│   └── 方向:Schema → Database
│
├── prisma db seed
│   ├── 作用:填充初始数据
│   ├── 场景:数据库初始化、测试数据
│   └── 方向:Script → Database
│
├── prisma db execute
│   ├── 作用:执行 SQL 语句
│   ├── 场景:执行原生 SQL、批量操作
│   └── 方向:SQL → Database
│
└── prisma migrate
│   ├── 作用:数据库迁移管理
│   ├── 场景:生产环境、团队协作
│   └── 方向:Schema + Migrations → Database

1.2 命令对比:db pull vs db push

维度db pulldb push
方向Database → SchemaSchema → Database
用途从数据库生成 Schema将 Schema 同步到数据库
场景已有数据库、数据库迁移原型开发、快速迭代
安全性只读操作,不会修改数据库可能修改数据库结构
推荐初始化项目时使用开发环境使用

二、prisma db pull 命令详解

2.1 命令基本用法

bash
# 基本用法
npx prisma db pull

# 指定 Schema 文件路径
npx prisma db pull --schema=./prisma/schema.prisma

# 打印结果但不写入文件
npx prisma db pull --print

# 强制覆盖现有 Schema
npx prisma db pull --force

2.2 命令参数详解

参数说明默认值
--schema指定 Schema 文件路径./prisma/schema.prisma
--print打印结果到控制台false
--force强制覆盖现有 Schemafalse
--url指定数据库连接 URL使用 DATABASE_URL

2.3 实战示例:从数据库同步 Schema

场景:修改数据库字段类型

步骤一:使用数据库管理工具修改表结构

sql
-- 在数据库管理工具中执行
-- 将 users 表的 phone 字段从 INT 改为 BIGINT
ALTER TABLE users MODIFY COLUMN phone BIGINT;

步骤二:使用 db pull 同步到 Schema

bash
# 执行同步命令
npx prisma db pull

# 输出示例
 Introspecting database

Writing to ./prisma/schema.prisma

 Generated Prisma Schema

步骤三:查看更新后的 Schema

prisma
// prisma/schema.prisma

model User {
  id        Int      @id @default(autoincrement())
  username  String   @unique
  password  String
  name      String
  phone     BigInt?  // 从 Int 改为 BigInt
  email     String   @unique
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  
  @@map("users")
}

2.4 db pull 工作原理

code
prisma db pull 工作流程:
│
├── 第一步:连接数据库
│   └── 使用 DATABASE_URL 连接
│
├── 第二步:读取数据库结构
│   ├── 表结构(表名、字段名、类型)
│   ├── 索引(主键、唯一索引、普通索引)
│   ├── 外键约束
│   └── 默认值
│
├── 第三步:生成 Prisma Schema
│   ├── 转换 SQL 类型为 Prisma 类型
│   ├── 生成 model 定义
│   └── 添加关系定义
│
└── 第四步:写入 schema.prisma
    └── 保存到指定路径

2.5 SQL 类型到 Prisma 类型映射

SQL 类型Prisma 类型说明
INTInt整数
BIGINTBigInt大整数
VARCHAR(n)String字符串
TEXTString长文本
BOOLEANBoolean布尔值
DATETIMEDateTime日期时间
DECIMAL(p, s)Decimal精确小数
FLOATFloat浮点数
JSONJsonJSON 数据

三、prisma db pull 最佳实践

3.1 使用场景一:已有数据库初始化项目

code
场景描述:
│
├── 已有数据库
│   ├── 运行中的生产数据库
│   ├── 遗留系统数据库
│   └── 第三方数据库
│
├── 需求
│   ├── 使用 Prisma 管理数据库
│   ├── 需要类型安全的查询
│   └── 不想手动编写 Schema
│
└── 解决方案
    ├── 使用 db pull 生成 Schema
    ├── 使用 prisma generate 生成 Client
    └── 开始使用 Prisma Client

完整流程

bash
# 1. 创建 Prisma 项目
mkdir my-project
cd my-project
npm init -y

# 2. 安装 Prisma
npm install prisma @prisma/client

# 3. 初始化 Prisma
npx prisma init

# 4. 配置数据库连接
# 编辑 .env 文件
DATABASE_URL="mysql://user:password@localhost:3306/mydb"

# 5. 从数据库拉取 Schema
npx prisma db pull

# 6. 生成 Prisma Client
npx prisma generate

# 7. 开始使用
node index.js

3.2 使用场景二:数据库迁移

code
数据库迁移场景:
│
├── 场景:MySQL → PostgreSQL
│
├── 第一步:从 MySQL 拉取 Schema
│   └── npx prisma db pull(连接 MySQL)
│
├── 第二步:调整 Schema
│   ├── 修改数据库提供者为 postgresql
│   ├── 调整不兼容的类型
│   └── 调整字段约束
│
├── 第三步:推送到 PostgreSQL
│   └── npx prisma db push(连接 PostgreSQL)
│
└── 第四步:迁移数据
    ├── 导出 MySQL 数据
    ├── 转换数据格式
    └── 导入 PostgreSQL

实战代码

bash
# 步骤 1:从 MySQL 拉取 Schema
# .env
DATABASE_URL="mysql://user:password@localhost:3306/mydb"

npx prisma db pull

# 步骤 2:修改 schema.prisma
# 将 provider 从 mysql 改为 postgresql
# datasource db {
#   provider = "postgresql"
#   url      = env("DATABASE_URL")
# }

# 步骤 3:切换到 PostgreSQL
# .env
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

# 步骤 4:推送到 PostgreSQL
npx prisma db push

# 步骤 5:迁移数据
# 使用数据迁移脚本
node migrate-data.js
javascript
// migrate-data.js
const { PrismaClient: MySQLClient } = require('./mysql-client');
const { PrismaClient: PostgresClient } = require('./postgres-client');

const mysql = new MySQLClient();
const postgres = new PostgresClient();

async function migrateData() {
  // 从 MySQL 读取数据
  const users = await mysql.user.findMany();
  
  // 写入 PostgreSQL
  for (const user of users) {
    await postgres.user.create({
      data: user,
    });
  }
  
  console.log('数据迁移完成!');
}

migrateData();

3.3 使用场景三:同步生产数据库结构

code
同步生产数据库结构:
│
├── 场景
│   ├── 生产数据库有变更
│   ├── 需要同步到开发环境
│   └── 需要更新 Prisma Schema
│
├── 流程
│   ├── 第一步:从生产环境拉取 Schema
│   ├── 第二步:生成迁移文件
│   ├── 第三步:在开发环境执行迁移
│   └── 第四步:测试验证
│
└── 注意事项
    ├── 不要直接连接生产数据库
    ├── 先备份再操作
    └── 使用只读副本或导出的 Schema

四、prisma db seed 命令详解

4.1 命令基本用法

bash
# 基本用法
npx prisma db seed

# 查看帮助
npx prisma db seed --help

4.2 配置 seed 脚本

方式一:在 package.json 中配置(推荐)

json
// package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "prisma": {
    "seed": "node prisma/seed.js"
  },
  "scripts": {
    "db:seed": "prisma db seed"
  }
}

方式二:在 schema.prisma 中配置

prisma
// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// 注意:seed 配置建议在 package.json 中

4.3 创建 seed 脚本

javascript
// prisma/seed.js
const { PrismaClient } = require('@prisma/client');

const prisma = new PrismaClient();

async function main() {
  // 清空现有数据
  await prisma.user.deleteMany();
  await prisma.post.deleteMany();
  await prisma.category.deleteMany();

  // 创建分类
  const categories = await Promise.all([
    prisma.category.create({
      data: { name: '技术' },
    }),
    prisma.category.create({
      data: { name: '前端' },
    }),
    prisma.category.create({
      data: { name: '后端' },
    }),
  ]);

  console.log('分类创建完成:', categories);

  // 创建用户
  const users = await Promise.all([
    prisma.user.create({
      data: {
        username: 'john_doe',
        email: 'john@example.com',
        password: '$2b$10$...', // 加密后的密码
        name: 'John Doe',
        phone: '13800138000',
      },
    }),
    prisma.user.create({
      data: {
        username: 'jane_doe',
        email: 'jane@example.com',
        password: '$2b$10$...',
        name: 'Jane Doe',
        phone: '13900139000',
      },
    }),
  ]);

  console.log('用户创建完成:', users);

  // 创建文章
  const posts = await Promise.all([
    prisma.post.create({
      data: {
        title: 'Prisma 入门教程',
        content: 'Prisma 是一个现代化的数据库工具...',
        published: true,
        authorId: users[0].id,
        categories: {
          connect: [
            { id: categories[0].id },
            { id: categories[1].id },
          ],
        },
      },
    }),
    prisma.post.create({
      data: {
        title: 'NestJS 实战指南',
        content: 'NestJS 是一个渐进式的 Node.js 框架...',
        published: true,
        authorId: users[1].id,
        categories: {
          connect: [
            { id: categories[0].id },
            { id: categories[2].id },
          ],
        },
      },
    }),
  ]);

  console.log('文章创建完成:', posts);

  console.log(' 数据填充完成!');
}

main()
  .catch((e) => {
    console.error(' 数据填充失败:', e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

4.4 使用 TypeScript 编写 seed 脚本

typescript
// prisma/seed.ts
import { PrismaClient, Prisma } from '@prisma/client';

const prisma = new PrismaClient();

const userData: Prisma.UserCreateInput[] = [
  {
    username: 'john_doe',
    email: 'john@example.com',
    password: '$2b$10$...',
    name: 'John Doe',
    phone: '13800138000',
  },
  {
    username: 'jane_doe',
    email: 'jane@example.com',
    password: '$2b$10$...',
    name: 'Jane Doe',
    phone: '13900139000',
  },
];

const categoryData: Prisma.CategoryCreateInput[] = [
  { name: '技术' },
  { name: '前端' },
  { name: '后端' },
];

async function main() {
  console.log('开始填充数据...');

  // 清空现有数据
  await prisma.post.deleteMany();
  await prisma.user.deleteMany();
  await prisma.category.deleteMany();

  // 创建分类
  const categories = await Promise.all(
    categoryData.map((data) => prisma.category.create({ data })),
  );
  console.log(`创建了 ${categories.length} 个分类`);

  // 创建用户
  const users = await Promise.all(
    userData.map((data) => prisma.user.create({ data })),
  );
  console.log(`创建了 ${users.length} 个用户`);

  // 创建文章
  const posts = await Promise.all([
    prisma.post.create({
      data: {
        title: 'Prisma 入门教程',
        content: 'Prisma 是一个现代化的数据库工具...',
        published: true,
        author: {
          connect: { id: users[0].id },
        },
        categories: {
          connect: [{ id: categories[0].id }, { id: categories[1].id }],
        },
      },
    }),
    prisma.post.create({
      data: {
        title: 'NestJS 实战指南',
        content: 'NestJS 是一个渐进式的 Node.js 框架...',
        published: true,
        author: {
          connect: { id: users[1].id },
        },
        categories: {
          connect: [{ id: categories[0].id }, { id: categories[2].id }],
        },
      },
    }),
  ]);
  console.log(`创建了 ${posts.length} 篇文章`);

  console.log(' 数据填充完成!');
}

main()
  .catch((e) => {
    console.error(' 数据填充失败:', e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
json
// package.json
{
  "prisma": {
    "seed": "ts-node prisma/seed.ts"
  },
  "devDependencies": {
    "ts-node": "^10.9.0",
    "typescript": "^5.0.0"
  }
}

4.5 seed 最佳实践

code
seed 最佳实践:
│
├── 1. 数据清理
│   ├── seed 前清空现有数据
│   ├── 注意清理顺序(外键约束)
│   └── 使用 deleteMany() 批量删除
│
├── 2. 数据一致性
│   ├── 使用事务处理
│   ├── 确保关联关系正确
│   └── 处理唯一约束
│
├── 3. 环境区分
│   ├── 开发环境:测试数据
│   ├── 测试环境:模拟数据
│   └── 生产环境:初始数据(管理员等)
│
├── 4. 可重复执行
│   ├── 幂等性设计
│   ├── 避免重复插入
│   └── 使用 upsert 代替 create
│
└── 5. 错误处理
    ├── 捕获异常
    ├── 回滚事务
    └── 记录日志

五、prisma db execute 命令详解

5.1 命令基本用法

bash
# 执行 SQL 文件
npx prisma db execute --file=./scripts/init.sql

# 执行 SQL 语句
npx prisma db execute --stdin <<< "SELECT * FROM users"

# 指定数据库 URL
npx prisma db execute --file=./scripts/init.sql --url=mysql://user:password@localhost:3306/mydb

# 指定 Schema 文件
npx prisma db execute --file=./scripts/init.sql --schema=./prisma/schema.prisma

5.2 命令参数详解

参数说明默认值
--file指定 SQL 文件路径-
--stdin从标准输入读取 SQL-
--url指定数据库连接 URL使用 DATABASE_URL
--schema指定 Schema 文件路径./prisma/schema.prisma

5.3 实战示例

示例一:执行初始化脚本

sql
-- scripts/init.sql
-- 创建索引
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_posts_author ON posts(author_id);

-- 创建视图
CREATE VIEW active_users AS
SELECT id, username, email, name
FROM users
WHERE deleted_at IS NULL;

-- 创建存储过程
DELIMITER //
CREATE PROCEDURE GetUserPosts(IN userId INT)
BEGIN
  SELECT * FROM posts WHERE author_id = userId;
END //
DELIMITER ;
bash
# 执行初始化脚本
npx prisma db execute --file=./scripts/init.sql

示例二:批量更新数据

sql
-- scripts/update-users.sql
-- 批量更新用户状态
UPDATE users
SET status = 'active'
WHERE last_login_at > DATE_SUB(NOW(), INTERVAL 30 DAY);

-- 批量清理过期数据
DELETE FROM sessions
WHERE expires_at < NOW();
bash
# 执行批量更新
npx prisma db execute --file=./scripts/update-users.sql

示例三:执行原生 SQL 查询

bash
# 查询用户数量
npx prisma db execute --stdin <<< "SELECT COUNT(*) FROM users"

# 创建新表
npx prisma db execute --stdin <<< "CREATE TABLE logs (id INT AUTO_INCREMENT PRIMARY KEY, message TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"

5.4 使用场景

code
prisma db execute 使用场景:
│
├── 1. 执行原生 SQL
│   ├── 创建存储过程
│   ├── 创建触发器
│   └── 创建视图
│
├── 2. 批量数据操作
│   ├── 批量更新
│   ├── 批量删除
│   └── 数据清理
│
├── 3. 数据库初始化
│   ├── 创建索引
│   ├── 设置权限
│   └── 初始配置
│
└── 4. 数据库维护
    ├── 性能优化
    ├── 空间清理
    └── 日志管理

六、数据库迁移最佳实践

6.1 db pull + migrate 组合使用

code
推荐的开发流程:
│
├── 场景一:新项目开发
│   ├── 编辑 schema.prisma
│   ├── npx prisma migrate dev --name init
│   └── 生成迁移文件
│
├── 场景二:已有数据库
│   ├── npx prisma db pull
│   ├── npx prisma migrate dev --name init
│   └── 建立迁移基线
│
└── 场景三:团队协作
    ├── 开发者 A:修改 Schema,执行 migrate
    ├── 提交迁移文件到 Git
    └── 开发者 B:拉取代码,执行 migrate

6.2 数据库迁移流程

bash
# 完整的数据库迁移流程

# 1. 从源数据库拉取 Schema
DATABASE_URL="mysql://..." npx prisma db pull

# 2. 调整 Schema(如需要)
# 编辑 schema.prisma

# 3. 创建初始迁移
npx prisma migrate dev --name init

# 4. 导出源数据库数据
mysqldump -u user -p mydb > backup.sql

# 5. 切换到目标数据库
# 修改 .env 中的 DATABASE_URL

# 6. 推送 Schema 到目标数据库
npx prisma db push

# 7. 导入数据到目标数据库
psql -U user -d mydb < backup.sql

# 8. 验证数据
npx prisma studio

6.3 数据库命令选择指南

场景推荐命令说明
新项目开发migrate dev生成迁移文件,团队协作
原型开发db push快速迭代,不生成迁移文件
已有数据库db pull + migrate dev建立迁移基线
生产环境migrate deploy只执行迁移,不生成新迁移
填充数据db seed初始化数据、测试数据
执行 SQLdb execute原生 SQL、特殊操作

七、完整实战示例

7.1 项目结构

code
my-project/
├── prisma/
│   ├── schema.prisma          # Prisma Schema
│   ├── seed.js                # Seed 脚本
│   └── migrations/            # 迁移文件
│       └── 20240101000000_init/
│           └── migration.sql
├── scripts/
│   ├── init.sql               # 初始化 SQL
│   └── cleanup.sql            # 清理 SQL
├── src/
│   └── index.js
├── .env                       # 环境变量
├── package.json
└── README.md

7.2 package.json 配置

json
{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "db:pull": "prisma db pull",
    "db:push": "prisma db push",
    "db:seed": "prisma db seed",
    "db:execute": "prisma db execute",
    "db:studio": "prisma studio",
    "migrate:dev": "prisma migrate dev",
    "migrate:deploy": "prisma migrate deploy",
    "migrate:reset": "prisma migrate reset",
    "generate": "prisma generate"
  },
  "prisma": {
    "seed": "node prisma/seed.js"
  },
  "dependencies": {
    "@prisma/client": "^5.0.0"
  },
  "devDependencies": {
    "prisma": "^5.0.0"
  }
}

7.3 完整操作流程

bash
# 1. 安装依赖
npm install

# 2. 配置数据库连接
# 编辑 .env
DATABASE_URL="mysql://user:password@localhost:3306/mydb"

# 3. 从已有数据库拉取 Schema
npm run db:pull

# 4. 生成 Prisma Client
npm run generate

# 5. 创建初始迁移
npm run migrate:dev -- --name init

# 6. 填充初始数据
npm run db:seed

# 7. 打开数据库管理界面
npm run db:studio

# 8. 执行 SQL 脚本
npm run db:execute -- --file=./scripts/init.sql

# 9. 推送 Schema 到数据库
npm run db:push

# 10. 重置数据库
npm run migrate:reset

八、常见问题与解决方案

8.1 db pull 无法识别某些类型

问题:某些 SQL 类型无法正确映射到 Prisma 类型。

解决方案

prisma
// 手动调整 Schema
model User {
  id        Int      @id @default(autoincrement())
  phone     BigInt?  // 手动调整类型
  status    String   // 枚举类型可能被识别为 String
  
  @@map("users")
}

// 可以定义枚举
enum Status {
  ACTIVE
  INACTIVE
  PENDING
}

8.2 seed 脚本报错

问题:执行 npx prisma db seed 报错。

解决方案

bash
# 检查 seed 配置
cat package.json | grep -A 2 "prisma"

# 手动执行 seed 脚本
node prisma/seed.js

# 检查 Prisma Client 是否生成
npx prisma generate

# 检查数据库连接
npx prisma db pull

8.3 db execute 权限不足

问题:执行 SQL 时权限不足。

解决方案

bash
# 检查数据库用户权限
# 使用有足够权限的用户

# 或者在数据库中授予权限
GRANT ALL PRIVILEGES ON mydb.* TO 'user'@'localhost';
FLUSH PRIVILEGES;

8.4 迁移冲突问题

问题:执行迁移时提示冲突。

解决方案

bash
# 查看迁移状态
npx prisma migrate status

# 标记迁移为已应用
npx prisma migrate resolve --applied "migration_name"

# 重置数据库(注意:会清空数据)
npx prisma migrate reset

九、命令速查表

9.1 数据库命令速查

命令作用常用参数
db pull从数据库同步 Schema--schema, --print, --force
db push推送 Schema 到数据库--accept-data-loss
db seed填充初始数据-
db execute执行 SQL--file, --stdin, --url
db drop删除数据库--force
db create创建数据库-

9.2 迁移命令速查

命令作用常用参数
migrate dev开发环境迁移--name, --create-only
migrate deploy生产环境部署迁移-
migrate reset重置数据库--force
migrate status查看迁移状态-
migrate resolve解决迁移问题--applied, --rolled-back

十、学习要点总结

10.1 核心概念总结

code
Prisma 数据库命令核心要点:
│
├── db pull
│   ├── 从数据库同步到 Schema
│   ├── 已有数据库初始化项目
│   └── 数据库迁移场景
│
├── db push
│   ├── 从 Schema 同步到数据库
│   ├── 快速原型开发
│   └── 不生成迁移文件
│
├── db seed
│   ├── 填充初始数据
│   ├── 测试数据生成
│   └── 需要在 package.json 配置
│
├── db execute
│   ├── 执行原生 SQL
│   ├── 创建存储过程、视图
│   └── 批量数据操作
│
└── migrate
    ├── 团队协作推荐
    ├── 版本控制
    └── 生产环境部署

10.2 命令选择指南

code
如何选择 Prisma 数据库命令:
│
├── 是否已有数据库?
│   ├── 是 → db pull + migrate dev
│   └── 否 → 直接编辑 Schema
│
├── 是否团队协作?
│   ├── 是 → migrate dev(生成迁移文件)
│   └── 否 → db push(快速迭代)
│
├── 是否需要填充数据?
│   ├── 是 → db seed
│   └── 否 → 跳过
│
└── 是否需要执行 SQL?
    ├── 是 → db execute
    └── 否 → 跳过

10.3 学习路径规划

code
学习路径规划:
│
├── 第一阶段:理解概念(1 天)
│   ├── 理解各命令的作用
│   ├── 理解命令执行方向
│   └── 理解使用场景
│
├── 第二阶段:实践操作(2-3 天)
│   ├── 使用 db pull 拉取 Schema
│   ├── 使用 db seed 填充数据
│   ├── 使用 db execute 执行 SQL
│   └── 使用 migrate 管理迁移
│
└── 第三阶段:深入应用(持续)
    ├── 数据库迁移实践
    ├── 团队协作流程
    └── 性能优化

10.4 重要提示

重要提示db pulldb push 是相反的操作,db pull 是从数据库同步到 Schema,db push 是从 Schema 同步到数据库。已有数据库时使用 db pull,新项目开发时使用 db pushmigrate dev。生产环境务必使用 migrate 系列命令,确保迁移可追溯、可回滚!


十一、参考资料