ORM、Schema 与数据库迁移
ORM 让应用用类型和对象访问数据库;迁移则记录结构如何从旧版本安全变化到新版本。
- 数据库结构变化有记录、可审查、可重复。
- Prisma / JPA 等 ORM 与 SQL 的关系
- 为现有表新增可空字段,生成迁移、检查 SQL、执行并验证旧数据。
- 完成 6.2「SQL 与关系型数据库直觉」
FOUNDATION
必须理解
ORM 让应用用类型和对象访问数据库;迁移则记录结构如何从旧版本安全变化到新版本。
ORM(Object-Relational Mapping,对象关系映射)把代码中的模型与数据库操作连接起来;迁移则记录数据库结构怎样从旧版本演进到新版本。便利不能替代对 SQL 和数据风险的理解。
ORM 像翻译员,把 TypeScript 对象翻成 SQL;迁移像建筑改造图纸,按顺序记录加门、改管线。翻译员和图纸都可能出错,所以施工前要审查。
Prisma schema 定义 User 与 Task,迁移创建表和外键,服务端通过 Prisma Client 查询当前用户任务;新增 dueAt 字段要生成并检查迁移。
Prisma / JPA 等 ORM 与 SQL 的关系
Prisma Schema 写清模型、字段、关系和约束,Prisma Client 再根据它生成带类型的查询方法。最后真正执行工作的仍然是数据库和 SQL。
基础概念
ORM(Object-Relational Mapping,对象关系映射)把程序中的类型或对象操作映射为数据库查询。Prisma、JPA 等减少重复代码,但底层仍由 SQL 与数据库执行。
进一步理解
ORM 模型描述字段、关系和约束,客户端提供类型化查询。它能防止部分拼接错误,却不会自动设计正确业务模型或高效查询。
复杂查询、事务和性能问题仍需理解生成的 SQL、索引与数据库行为。不同 ORM 的加载策略也可能造成大量隐形请求。
代码通过 `task.findMany({where:{ownerId}})` 查询任务,ORM 生成参数化 SQL;开发者仍要确认只返回当前用户且没有 N+1 查询。
ORM 不是数据库,也不是 SQL 替代物;它是应用与关系型数据库之间的一层映射和工具。
这一小节记住:使用 ORM 提高表达和类型安全,同时保留检查数据库行为的能力。
Schema、客户端、查询和关系加载
迁移文件记录数据库结构每一步怎么变化,像 Git 记录代码历史。开发时可以反复试,到了生产环境就得考虑旧数据、锁表时间和失败后怎么处理。
基础概念
Schema 是数据结构与约束的声明,生成客户端把声明转换为可调用 API,关系加载决定查询时是否以及怎样取得关联记录。
进一步理解
一对多关系通常由“多”方保存外键。是否一起加载关联数据应由当前用例决定,默认全部加载会增加查询和传输。
Schema 改变只是代码层意图,真实数据库还需迁移。生成客户端也需与新 Schema 同步,否则类型和数据库会处于不同版本。
Task 的 ownerId 保存外键,owner 描述 ORM 关系;列表页只选择任务字段,详情页需要时再加载所有者公开信息。
类型中的可选字段与数据库可空约束相关但不完全相同;应用没传值、数据库默认值与实际 NULL 要分别理解。
这一小节记住:Schema 描述数据契约,查询应只加载当前行为需要的字段与关系。
迁移文件、开发数据库与生产数据库
如果旧表里已经有一万行数据,突然加一个必填字段,这一万行都没有值。更稳的做法通常是先允许为空、完成回填,再把约束收紧。
基础概念
迁移文件记录数据库结构从一个版本变到下一个版本的具体步骤。开发库用于试验,生产库含真实数据,执行策略必须考虑兼容、锁表、回填和失败恢复。
进一步理解
新增非空字段时,旧行没有值。安全过程常分为增加可空字段、部署兼容代码、回填旧数据、再收紧约束。
迁移应进入版本控制并先在含真实规模副本上演练。直接手改生产表会让源码、迁移历史和实际结构失去一致。
为任务增加 priority:先允许为空并让新代码兼容,批量回填默认值,验证无 NULL 后再添加非空约束。
代码回滚不自动回滚数据库。某些结构删除和数据转换不可逆,必须单独设计向前修复或恢复方案。
这一小节记住:数据库结构变化要被记录、审查、演练,并与应用版本保持兼容。
- Prisma Schema 中已经存在 User 模型及其 tasks 反向关系。
- 生成迁移前确认目标数据库与现有数据,不直接对生产执行开发重置。
model Task {
id String @id @default(cuid())
title String
done Boolean @default(false)
ownerId String
owner User @relation(fields: [ownerId], references: [id])
createdAt DateTime @default(now())
}ownerId 是外键值,owner 描述 Prisma 层关系;数据库迁移会建立相应约束。
- id 使用 cuid 生成主键,done 与 createdAt 由数据库/客户端提供默认值。
- ownerId 保存真实外键值,owner 声明该字段引用 User.id。
- 修改模型后需生成并审查迁移 SQL,再更新客户端类型。
迁移创建任务表、外键和默认值;无效 ownerId 被约束拒绝,查询时可以按需加载 owner,而不是复制用户数据。
AI COLLABORATION
AI 如何参与
让 AI 生成迁移后必须检查实际 SQL,确认没有意外删除、重建或丢失数据。
推荐协作顺序
- 1
把当前 schema、目标变化和已有数据情况发给 AI。
- 2
让它先说明旧数据会遇到什么,再给分阶段迁移方案。
- 3
生成迁移后请它解释 SQL,但最终以测试数据库的真实结果为准。
请为 Next.js + PostgreSQL + Prisma 的任务应用设计 User、Task 模型。Task 包含 id、title、done、ownerId、createdAt。先解释关系和删除策略,再给 schema。随后模拟新增必填 dueAt,说明为什么不能直接上线以及安全迁移步骤。
模型有清晰主键、外键和时间字段;迁移方案考虑旧数据,不只给 prisma migrate 命令。
人工检查清单
- 确认没有保存明文密码,级联删除符合产品意图,生成的迁移 SQL 会被人工检查。
- 让 AI 展示迁移实际 SQL、旧数据处理和新旧应用并存时的兼容路径。
- 在含旧数据的测试副本执行迁移、回退或恢复演练,并核对行数与约束。
COMMON TRAPS
常见误区
错误不是需要隐藏的失败,而是帮助你看清系统边界的证据。下面三类问题在 AI 辅助学习中最常出现。
生成迁移后直接上线
- 你会看到
- 只看到命令成功,没有读它将删除或重建什么。
- 为什么发生
- ORM 的便捷 API 会隐藏生成 SQL,未经检查的关系加载可能产生大量查询或越过归属条件。
- 怎样纠正
- 检查迁移 SQL,在带旧数据的副本上完整跑一遍。
给旧表直接加必填字段
- 你会看到
- 历史记录没有值,迁移立刻失败。
- 为什么发生
- 直接改生产库没有可重复历史,其他环境无法同步,下一次自动迁移还可能误判当前状态。
- 怎样纠正
- 先允许为空或提供默认值,回填以后再收紧约束。
把 ORM 当成不用懂 SQL
- 你会看到
- 查询很慢或关系异常时,只会继续换 ORM 写法。
- 为什么发生
- 破坏性重置为开发空库设计,会删除数据,不应出现在生产修复流程。
- 怎样纠正
- 查看生成的 SQL、索引和数据库约束,理解最终执行发生在哪里。
HANDS-ON
动手任务
为现有表新增可空字段,生成迁移、检查 SQL、执行并验证旧数据。
- 完成 6.2「SQL 与关系型数据库直觉」
跟着做
- 01
安装并初始化 Prisma,连接本地 PostgreSQL。
- 02
定义 User、Task 及一对多关系。
- 03
生成第一份迁移并阅读 SQL。
- 04
写 seed 或脚本创建一名用户与任务。
- 05
用 Prisma Client 完成创建、查询、更新并核对数据库。
数据库结构变化有记录、可审查、可重复。
新增 dueAt 可选字段,写出从可选到必填的两阶段迁移计划。
离开本课前,自问四件事
- ORM、Schema、生成客户端与数据库分别承担什么?
- 关系加载为什么要按用例选择而不是默认全部取得?
- 给有旧数据的表新增必填字段应怎样分阶段?
- 为什么应用代码回滚并不保证数据库也能回到原状态?
确认完成后,会同步更新学习中心的课程学习进度。