首页 / Prisma ORM 入门教程 / 种子数据:v7 的 Seeding 新姿势

Prisma ORM 入门教程

种子数据:v7 的 Seeding 新姿势

本教程共 54 篇 · 第 33 篇 · 更新于 2026-08-11 · 约 6 分钟阅读

Prisma种子数据Seedingprisma db seedupsertcreateManyFakerprisma.config.ts

本节目标:学会配置并运行种子脚本,写出可重复执行的幂等种子,并掌握 v7 中 seeding 的行为变化。

种子数据解决什么问题

种子数据(seeding)就是给数据库填充初始数据:应用启动必需的默认配置,或者开发环境用来调试的假数据。有了种子脚本,同事拉下代码、重置数据库后,一条命令就能得到一致的初始状态。

什么时候该用种子?两种典型场景:一是应用启动依赖的默认数据(默认语言、默认币种、管理员账号),二是开发联调需要的演示数据(几十个用户、几百篇文章)。前者进了生产也要跑,后者通常只在开发环境跑——靠下文的自定义参数区分环境。

配置:prisma.config.ts 的 migrations.seed

v6 时代种子命令写在 package.json"prisma" 字段里,v7 挪进了 prisma.config.ts

import "dotenv/config";
import { defineConfig, env } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});

migrations.seed 可以是任意命令:tsx 跑 TypeScript、node 跑编译后的 JS、psql file.sql 跑 SQL,甚至 bash seed.sh 调用其他语言。

prisma db seed 本身不做什么,只是把 migrations.seed 里的命令原样执行。所以换脚本语言、换脚本名都不影响使用方式——改配置即可。

种子脚本里不要写死连接字符串,统一从环境变量读——和应用的方式一致。.env 由 dotenv 加载,脚本开头 import "dotenv/config" 即可。路径用项目相对路径,别用绝对路径,保证同事克隆后能直接跑。

Warning

v7 行为变化:migrate devmigrate reset 不再自动运行种子脚本。想要数据,显式执行 npx prisma db seed。忘了这一点,重置后看到空表别惊讶。

写第一个种子脚本

import "dotenv/config";
import { Pool } from "pg";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter: new PrismaPg(pool) });

async function main() {
  await prisma.user.upsert({
    where: { email: "alice@prisma.io" },
    update: {},
    create: { email: "alice@prisma.io", name: "Alice" },
  });
}

main()
  .then(async () => {
    await prisma.$disconnect();
    await pool.end();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    await pool.end();
    process.exit(1);
  });

v7 里 Prisma Client 必须带驱动程序适配器(driver adapter),这和应用的写法一致。注意收尾:$disconnect 关客户端,pool.end() 关连接池,否则脚本会挂住不退出。

脚本结构固定三段:初始化(建连接池、实例化 Client)、main 函数里写数据、收尾(断开连接)。错误处理记得 process.exit(1),否则 CI 里脚本失败了退出码还是 0,流水线照常绿。

幂等:种子的第一原则

种子脚本会被反复执行。所谓幂等,就是跑一次和跑一百次结果一样。

最稳妥的写法是用 upsert:按唯一字段查找,存在就更新,不存在就创建。上面例子里的 update: {} 表示「存在则什么都不改」。

批量插入用 createManyskipDuplicates,重复执行时跳过冲突行:

await prisma.user.createMany({
  data: users,
  skipDuplicates: true,
});

注意:skipDuplicates 依赖数据库的唯一约束。字段没有 @unique,重复数据照样插进去,幂等无从谈起——先建模,再谈幂等。

Tip

另一种常见策略是开头先 deleteMany 清空再插入。简单直接,但会重置自增 ID;有外键引用时要按子表先删、父表后删的顺序执行。deleteMany 策略适合数据完全由种子生成的测试库,upsert 策略适合要保留人工改动数据的库。两种都行,选一种保持一致。

判断种子是否幂等的标准:连续跑两次,第二次不报错、不产生重复数据。团队里任何人在任何时间点都能安全重跑,这条标准值得写进代码评审清单。

执行顺序也影响幂等:先造父表数据,再造子表;先清空子表,再清空父表。顺序反了,外键约束会直接报错。

造数据三件套

Faker 生成随机假数据,faker.seed(n) 固定随机种子,让每次生成的结果可复现:

import { faker } from "@faker-js/faker";
faker.seed(42);

const users = Array.from({ length: 50 }, () => ({
  email: faker.internet.email(),
  name: faker.person.fullName(),
}));
await prisma.user.createMany({ data: users });

CSV 导入脱敏后的真实数据:csv-parse 解析文件,每行按 Zod Schema 校验,最后 createMany 批量写入。适合导入存量数据。

工厂函数把造数逻辑封装成可复用的函数,测试和种子共用一份:

const userFactory = (overrides = {}) => ({
  email: faker.internet.email(),
  role: "USER",
  ...overrides,
});

数据量大时按 1k–10k 条分批 createMany;几百万行直接上数据库的 COPY 命令,别走 ORM。

关联数据:父子一起造

种子数据往往有依赖关系,父表先建、子表后建。嵌套写入一次搞定:

await prisma.user.create({
  data: {
    email: "demo@example.com",
    posts: { create: [{ title: "欢迎" }, { title: "你好" }] },
  },
});

posts.create 会连同用户一起创建,外键自动填上。已经存在的用户可以用 connect 复用,避免重复创建。嵌套 create 是一次事务,要么全部成功要么全部失败,不会留下半截数据。

用原始 SQL 补数据

少量固定数据可以直接用 $executeRaw 写进种子脚本,幂等靠 ON CONFLICT DO NOTHING

await prisma.$executeRaw`
  INSERT INTO "User" ("email", "name")
  VALUES ('foo@example.com', 'Foo')
  ON CONFLICT DO NOTHING;
`;

比起维护一个 .sql 文件再配 psql,这种方式省去了连接字符串和二进制的依赖。

带参数运行

prisma db seed 支持透传自定义参数,-- 后面接参数:

npx prisma db seed -- --environment test

脚本里用 Node 内置的 node:utilparseArgs 读取,一个脚本就能服务多套环境。参数化还能做增量种子:-- --only users 只重建用户表,省去全量重跑的时间。

Note

种子脚本不是迁移,它只管数据、不管结构。结构变更永远走迁移,数据填充走 seed,两条线别混。

参考来源

  • Prisma 官方文档:Seeding
  • Prisma 官方文档:prisma db seed
  • Mapagam:Seeding database data
  • DevSheets:Database seeding