第 0x07 章:Prisma 数据迁移 & 种子数据 ------ "把大象塞进冰箱"的优雅姿势
📚 目录(点击可直接瞬移)
- 🧬 迁移的本质:从 0 到 1,再从 1 到 ∞
- 🚧 迁移三步曲:
migrate dev
→migrate deploy
→db push
- 🌱 种子数据:给数据库撒一把"魔法豆"
- 🎩 实战:把大象(schema)塞进冰箱(PostgreSQL)
- 🔥 踩坑急救包:当
migrate deploy
甩你一脸 ERROR - 🧩 彩蛋:让种子数据自带"表情包"
1. 🧬 迁移的本质:从 0 到 1,再从 1 到 ∞
"在 SQLite 里,你可以随时
rm -rf dev.db
;但在生产 PostgreSQL,你敢
DROP DATABASE production
?恭喜,DevOps 会把你做成刺身。"
数据库迁移(Migration)的本质是------
把「意图」翻译成「可重放的 SQL 脚本」 。
就像把产品经理的 "我要一个五彩斑斓的黑" 翻译成 ALTER TABLE ... ADD COLUMN color VARCHAR(7) DEFAULT '#000000';
Prisma 的魔法在于:
- 用 声明式 schema 描述意图
- 用 版本化 SQL 文件 记录步骤
- 用 可回滚事务 保证原子性
2. 🚧 迁移三步曲
命令 | 适用场景 | 底层干的脏活累活 |
---|---|---|
prisma migrate dev |
本地开发 | 计算 diff → 生成 SQL → 执行 → 写入 _prisma_migrations 表 |
prisma migrate deploy |
CI/CD | 只做"执行"不做"diff",保证幂等 |
prisma db push |
快速原型 | 直接 CREATE TABLE IF NOT EXISTS ,不生成迁移文件(⚠️ 高危) |
可以把它们想成:
migrate dev
是 边开车边修路migrate deploy
是 高铁准点发车db push
是 F1 换轮胎------快,但容易着火
3. 🌱 种子数据:给数据库撒一把"魔法豆"
"没有种子的数据库,就像没有彩蛋的游戏------能跑,但索然无味。"
Prisma 官方推荐把种子脚本放在 prisma/seed.js
,并在 package.json
声明:
json
"prisma": {
"seed": "node prisma/seed.js"
}
运行方式:
bash
npx prisma db seed # 等价于 node prisma/seed.js
4. 🎩 实战:把大象塞进冰箱
Step 1:初始化项目
bash
npx create-next-app@latest next-prisma-magic --typescript --tailwind --eslint
cd next-prisma-magic
npm install prisma @prisma/client
npx prisma init
Step 2:schema.prisma ------ 描述我们的"大象"
prisma
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Wizard {
id Int @id @default(autoincrement())
name String
spell String
manaCost Int
createdAt DateTime @default(now())
}
🖼️ 示意图:一只穿长袍的大象,手里拿着魔杖,旁边写着 "Wizard"。
Step 3:创建 .env
并连上 PostgreSQL
bash
# .env
DATABASE_URL="postgresql://magic_user:secret@localhost:5432/magic_db"
Step 4:第一次迁移
bash
npx prisma migrate dev --name init_wizard_table
执行后,Prisma 会:
- 计算 schema 与数据库的差异
- 生成
prisma/migrations/20250822120000_init_wizard_table/migration.sql
- 在
_prisma_migrations
表插入一条记录(类似 Git 的 commit hash)
Step 5:撒种子 ------ prisma/seed.js
js
// prisma/seed.js
const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
async function main() {
const gandalf = await prisma.wizard.upsert({
where: { id: 1 },
update: {},
create: {
name: 'Gandalf',
spell: 'You shall not pass!',
manaCost: 9000,
},
})
const merlin = await prisma.wizard.upsert({
where: { id: 2 },
update: {},
create: {
name: 'Merlin',
spell: 'Abracadabra',
manaCost: 42,
},
})
console.table([gandalf, merlin])
}
main()
.catch(e => {
console.error('💥 种子爆炸:', e)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})
跑种子:
bash
npx prisma db seed
控制台输出:
lua
┌---------┬----┬---------┬-------------------------┬----------┐
│ (index) │ id │ name │ spell │ manaCost │
├---------┼----┼---------┼-------------------------┼----------┤
│ 0 │ 1 │ Gandalf │ 'You shall not pass!' │ 9000 │
│ 1 │ 2 │ Merlin │ 'Abracadabra' │ 42 │
└---------┴----┴---------┴-------------------------┴----------┘
5. 🔥 踩坑急救包
症状 | 病因 | 解药 |
---|---|---|
migrate deploy 报 P3009 |
数据库 schema 与迁移历史不一致 | 先用 migrate resolve --rolled-back 回滚,再重跑 |
种子脚本跑两次导致唯一键冲突 | 没用 upsert 或缺少 where |
把 create 改成 upsert |
CI 上 DATABASE_URL 没读到 |
GitHub Actions 没配置 Secret | 在仓库 → Settings → Secrets and variables → Actions 里加 |
6. 🧩 彩蛋:让种子数据自带"表情包"
在 seed.js
里加点小彩蛋:
js
const spells = [
{ name: 'Dobby', spell: '🧦 Dobby is free!', manaCost: 1 },
{ name: 'Hermione', spell: "📚 It's leviOsa, not levioSA!", manaCost: 1337 },
]
for (const s of spells) {
await prisma.wizard.create({ data: s })
}
运行后,数据库里就会出现一行行会眨眼的 emoji,
让 SELECT * FROM wizard
的查询结果像弹幕一样欢快。
🏁 结语
恭喜你!
现在你已经掌握了把大象(schema)塞进冰箱(PostgreSQL)的优雅姿势,
还顺手给冰箱贴上了会动的冰箱贴(种子数据)。
下一章,我们将用 Next.js 13 的 App Router + Server Actions 把魔杖交到前端手里。
敬请期待 ------
"前端:我要一个五彩斑斓的黑。
后端:给你返回
#000000
。全栈:给你返回
#000000
并附赠box-shadow: 0 0 20px #bada55;
"
🔮 彩蛋口令:在评论区打出
prisma migrate dev --create-only
召唤一次"只生成 SQL 不执行"的魔法!