7.6 数据库迁移实战
Tip
学会管理数据库的生命周期,让你的每一次数据库变更都可追踪、可回滚。
1. 为什么要学这个?
你在本地给用户表加了一个 age 字段,代码跑得很开心。
然后你把代码部署到线上。
注意看:线上的代码更新了,但线上的数据库还没变!
线上代码试图去读取 age,但数据库里根本没这个列。
程序当场崩溃。
你可能会想:"那我手动去线上数据库加个列不就行了?" 这就像你在玩游戏时不做存档,直接去改游戏文件。 一旦你手抖删错了一列,或者把测试数据污染到了生产环境,没有任何后悔药可吃。
掌握 Migration(迁移),就像给数据库装了"时光机"——每一次修改都被自动记录为历史存档,如果你搞砸了,随时可以回滚。
2. 核心概念
Migration (迁移) 体现为你的项目里的一堆 .sql 文件。
通常在 prisma/migrations 文件夹里。
不再"裸奔"
它解决了**"版本同步"**的问题。你的代码用 Git 管理,你的数据库结构用 Migration 管理。这样,你的数据库就能跟上代码的步伐,永远保持步调一致。
没有 Migration (裸奔):
你需要拿个小本本记着:"上线前记得去数据库执行 ALTER TABLE ADD COLUMN age..."。如果忘了,线上就炸。
有了 Migration (全自动): 你只需要运行一个命令,Prisma 会自动检测:"哦,你上次存档是版本3,现在是版本4,我来帮你把数据库自动升级到版本4。"
核心流程图
graph TD
Local[你的电脑] -->|修改 schema| Code["schema.prisma"]
Code -->|生成存档| SQL["SQL文件 (Migration)"]
SQL -->|上传| Git["Git 仓库"]
Git -->|部署| Server[线上服务器]
Server -->|自动执行 SQL| DB_Prod[线上数据库]
style DB_Prod fill:#e3f2fd,stroke:#1565c0
3. 实战体验
第一步:修改设计
你在 schema.prisma 里加了个字段:
model User {
id Int @id
name String
age Int? // 新加的
}
第二步:生成存档
运行命令:
npx prisma migrate dev --name add_age
这时候 Prisma 会做两件事:
- 自动在
migrations文件夹里生成一个 SQL 文件(比如20240101_add_age.sql)。 - 自动把这个 SQL 执行到你的本地数据库。
第三步:上线
当你把代码推送到线上,云平台会自动检测到这个新生成的 SQL 文件,并把它应用到线上数据库。
4. 避坑指南
| ❌ 不要这样做 | ✅ 应该这样做 | 💡 为什么 |
|---|---|---|
把 migrations 文件夹加入 .gitignore |
必须把 migrations 提交到 Git | 它是数据库的"历史档案",队友和线上环境都需要它来同步数据库结构。 |
| 手动去数据库改表结构 | 永远通过修改 schema.prisma 来改 |
手动改了,Prisma 不知道,下次生成迁移文件时会冲突报错。 |
在生产环境运行 migrate dev |
生产环境用 migrate deploy |
dev 命令会尝试重置数据库(清空数据!),这是新手把生产库删库的头号原因。 |
5. 真实案例
Story
Knight Capital 的 4.4 亿美元蒸发事故 (2012)
2012年,美国骑士资本 (Knight Capital) 在一次软件更新中犯了一个致命错误:工程师手动部署了新代码,却忘记更新服务器上的一个旧配置(这就像你改了 schema 但忘了跑 migrate)。 这个看似微不足道的环境不一致问题,导致新代码逻辑错乱,开始疯狂地在市场上高价买入、低价卖出股票。 仅仅 45 分钟,公司就亏损了 4.4 亿美元,直接导致这家华尔街巨头破产被收购。
Vibe 心法:人为操作是最大的安全隐患。Migration 是保证所有环境(开发、测试、生产)绝对一致的唯一手段。不要相信你的记忆,要相信代码生成的 SQL 文件。
6. 本章小结
- ⏳ 时光机:Migration 就是数据库的历史存档。
- 🤖 自动化:用代码去管理数据库结构,而不是手动去改。
- 🚨 生死命令:本地用
dev,线上用deploy,记不住就把它写进部署脚本里。