38 分钟
AI 时代的全栈 App 开发实战

用 AI 写后端与数据库:Schema 设计、迁移、测试、调试

掌握用 AI 辅助后端开发的完整流程:数据库 Schema 设计、数据迁移、API 实现、测试生成、性能优化、Bug 调试,避开 AI 生成后端代码的常见陷阱

  • 就说用 AI 搭数据库 Schema 的事儿,核心就盯这几个点:实体关系、字段类型、索引、约束、关联。
  • 理解数据库迁移(Migration)的概念和工具(Prisma/Alembic/Flyway),学会用 AI 生成迁移脚本
  • 掌握用 AI 生成 API 接口代码的正确姿势:先写接口契约,再让 AI 实现,最后审查测试
  • 学会用 AI 生成测试用例,包括单元测试、集成测试、边界测试,理解测试覆盖率的意义
  • 掌握用 AI 调试后端 Bug 的方法:把报错信息、相关代码、上下文给 AI,让它分析根因
  • 就说AI生成后端代码的几个常见坑:SQL注入、N+1查询、事务缺失、并发问题、性能问题

AI 写后端的正确工作流

后端开发比前端更需要想清楚再动手——因为后端涉及数据结构、业务逻辑、安全、性能,一旦设计错了,后期改造成本很高(数据迁移、API 不兼容、老数据修复)。用 AI 写后端的正确工作流是六步:

示例代码(可运行)

第一步:用 AI 设计数据库 Schema

数据库 Schema 设计是后端的根基——设计好了,后续开发顺畅;设计错了,后期数据迁移痛苦不堪。用 AI 设计 Schema 的正确方法是:先描述业务场景和实体关系给 AI;让 AI 生成 ER 图(实体关系图)和初始 Schema;你审查和调整(字段类型、索引、约束、关联);迭代到满意为止。

Python
// 用 AI 设计 Schema 的提示词示例
// """
// 你是一个有 10 年经验的数据库架构师,精通 PostgreSQL。
// 
// 业务场景:一个在线学习平台,包含以下实体:
// - 用户(User):id, 邮箱, 密码哈希, 昵称, 头像, 角色(学习者/管理员), 注册时间
// - 课程(Course):id, 标题, 描述, 封面图, 作者ID, 难度(入门/中级/高级), 价格, 创建时间
// - 课时(Lesson):id, 课程ID, 标题, 内容(富文本), 排序, 时长(分钟)
// - 学习进度(Progress):id, 用户ID, 课时ID, 状态(未开始/学习中/已完成), 最后学习时间, 完成时间
// - 练习(Exercise):id, 课时ID, 类型(选择题/代码题), 题目内容, 答案, 分值
// - 答题记录(Answer):id, 用户ID, 练习ID, 用户答案, 是否正确, 得分, 提交时间
// 
// 要求:
// 1. 用 PostgreSQL 语法,给出完整的 CREATE TABLE 语句
// 2. 所有表都要有主键(id,BIGSERIAL)、created_at、updated_at
// 3. 外键约束要明确(ON DELETE 策略)
// 4. 常用查询字段要加索引(用户邮箱、课程作者、学习进度的用户+课时)
// 5. 字段类型要合理(邮箱用 TEXT UNIQUE、状态用 ENUM 或 CHECK、时间用 TIMESTAMPTZ)
// 6. 给出 ER 图描述(实体之间的关系:一对一/一对多/多对多)
// 7. 说明每个索引的用途(为什么要加这个索引)
// """
print("给 AI 清晰的业务实体和要求,它能生成高质量的 Schema")
🐍Schema 设计的审查清单

AI 生成 Schema 后,逐项审查:字段类型是否合理(金额用 NUMERIC 不用 FLOAT!时间用 TIMESTAMPTZ 不用 TIMESTAMP!枚举用 ENUM 或 CHECK 不用 VARCHAR 随意存);主键策略(自增 BIGSERIAL / UUID / 雪花 ID,分布式系统用 UUID 或雪花);外键和 ON DELETE 策略(CASCADE/SET NULL/RESTRICT,删用户时他的学习进度怎么办?);索引是否合理(常用 WHERE/JOIN/ORDER BY 的字段要加索引,但不要过度索引——索引会降低写入性能、占空间);唯一约束(邮箱、用户名必须 UNIQUE);NOT NULL 约束(哪些字段不能为空);默认值(created_at DEFAULT now()、状态 DEFAULT '未开始');软删除还是硬删除(要不要加 deleted_at 字段做软删除);多租户隔离(如果是 SaaS,要不要加 tenant_id 和行级安全 RLS);数据量预估(哪些表会很大,需要分区或归档)。

第二步:数据库迁移(Migration)

数据库 Schema 不是一成不变的——产品迭代会加字段、加表、改结构。数据库迁移就是「把数据库从一个版本结构变到另一个版本结构」的脚本,每次变更都有一个迁移文件,包含 up 和 down:升级和回滚。主流工具:Prisma(Node/TypeScript,Schema 定义文件自动生成迁移,最现代)、Alembic(Python/SQLAlchemy)、Flyway(Java,SQL 文件)、golang-migrate(Go)。

示例
// Prisma 迁移示例(Node/TypeScript 最现代的 ORM)
// schema.prisma 文件:
// model User {
//   id        BigInt   @id @default(autoincrement())
//   email     String   @unique
//   name      String?
//   role      Role     @default(LEARNER)
//   createdAt DateTime @default(now())
//   updatedAt DateTime @updatedAt
//   lessons   Progress[]
// }
//
// model Lesson {
//   id       BigInt   @id @default(autoincrement())
//   courseId BigInt
//   title    String
//   content  String?
//   course   Course   @relation(fields: [courseId], references: [id])
// }
//
// 命令行:
// npx prisma migrate dev --name add_user_table  // 生成并执行迁移
// npx prisma migrate deploy                      // 生产环境执行迁移
// npx prisma studio                              // 打开可视化数据库管理界面
//
// 迁移文件会生成在 prisma/migrations/ 目录下,每个迁移一个时间戳命名的文件夹,
// 包含 migration.sql(SQL 语句),可以进版本控制,团队共享。
💡用 AI 生成迁移脚本

给 AI 看当前的 Schema(或 Prisma schema 文件)和你想要的变更(如「给 User 表加一个 phone 字段,给 Lesson 表加一个 difficulty 枚举」),让 AI 生成迁移 SQL。注意:AI 生成的迁移要审查(字段类型、默认值、是否需要回填数据、是否锁表——大表加字段可能需要用并发操作避免锁表);生产环境的大表变更要小心(加 NOT NULL 字段无默认值会锁表、加索引要用 CONCURRENTLY);永远要有 down(回滚)脚本,迁移失败能回退;迁移前备份数据库;迁移进版本控制(Git),团队共享。

第三步:让 AI 实现 API 接口

Schema 和 API 契约设计好后,让 AI 写接口代码。给 AI 看:技术栈(Express/Fastify/Nest + Prisma/TypeORM)、API 契约(URL/方法/参数/响应)、Schema 定义、相关已有代码(让 AI 模仿你的代码风格和模式),然后让它生成接口实现。一次只让 AI 实现一个或几个相关接口,别让它一次写整个后端。

Python
// 让 AI 实现 API 的提示词示例
// """
// 你是一个有 10 年经验的 Node.js 后端工程师,精通 Express + TypeScript + Prisma + PostgreSQL。
// 
// 技术栈:
// - 框架:Express + TypeScript
// - ORM:Prisma
// - 数据库:PostgreSQL
// - 验证:zod
// - 认证:JWT(从 Authorization: Bearer <token> 解析,中间件 authMiddleware 已存在)
// 
// 请实现以下 API 接口(参考已有的 user.routes.ts 的代码风格):
// 
// 1. POST /api/v1/courses
//    - 描述:创建课程(仅管理员可创建)
//    - 请求体:{ title: string, description: string, difficulty: 'BEGINNER'|'INTERMEDIATE'|'ADVANCED', price: number }
//    - 响应:201 Created,返回创建的课程对象
//    - 权限:需要登录且 role=ADMIN
//    - 验证:title 1-100字符,description 最多2000字符,price >=0
// 
// 2. GET /api/v1/courses
//    - 描述:获取课程列表(分页+按难度筛选+按创建时间排序)
//    - 查询参数:page(默认1), page_size(默认20,最大50), difficulty(可选), sort(可选, 'newest'|'oldest'|'popular')
//    - 响应:200 OK,{ data: Course[], total: number, page: number, page_size: number }
//    - 权限:公开(不需要登录)
// 
// 3. GET /api/v1/courses/:id
//    - 描述:获取单个课程详情(含课时列表)
//    - 响应:200 OK,返回课程对象+lessons数组
//    - 404:课程不存在
// 
// 要求:
// - 用 zod 做输入验证,验证失败返回 400 + 统一错误格式
// - 用 Prisma Client 做数据库操作
// - 数据库错误要 catch,返回 500 + 统一错误格式,日志记录详情
// - 代码要有中文注释
// - 遵循已有的代码结构(routes/controller/service 分层)
// """
print("给 AI 技术栈+契约+Schema+已有代码风格,它能生成高质量的接口实现")

第四步:审查 AI 生成的后端代码

AI生成的后端代码不能直接用,必须审查。后端代码的审查重点比前端更多——因为后端错误会导致数据泄露、数据损坏、安全漏洞、性能崩溃。

填空题填写空白处的代码
# AI 后端代码审查清单(填空) # 1. 安全:有没有 SQL 注入(用了字符串拼接而不是参数化)?有没有(用户输入未转义)?有没有权限检查? # 2. 输入验证:所有参数都验证了吗(类型/长度/格式/范围)?有没有用/Joi? # 3. 错误处理:所有异步操作都有 try/catch 吗?数据库错误/网络错误/超时都处理了吗? # 4. 事务:多个写操作有没有用包裹?(如创建订单同时扣库存,必须原子性) # 5. N+1 查询:循环里查数据库了吗?应该用 JOIN 或一次查出关联数据 # 6. 索引:常用查询字段有索引吗?EXPLAIN 看查询计划了吗? # 7. 并发:有没有竞态条件?(如两个请求同时扣库存,超卖)需要乐观锁/悲观锁/原子操作 # 8. 性能:有没有查全表(SELECT * 无 LIMIT)?有没有大事务?有没有 N+1? # 9. 敏感信息:密码哈希了吗?API Key 存在环境变量吗?响应里有没有返回敏感字段? # 10. 日志:关键操作有日志吗?日志里有没有打印敏感信息(密码/Token)?
⚠️AI 生成后端代码的五个高频陷阱

N+1 查询:AI 喜欢在循环里查数据库(如遍历课程列表,每个课程再查一次作者信息),10个课程就11次查询。应该用 JOIN/include 一次查出。审查时看到循环里有 await db.query 就要警惕。事务缺失:AI 写「创建订单+扣库存」时可能分开写两个操作,中间失败会导致数据不一致(订单创建了但库存没扣,或反过来)。多个写操作必须用事务包裹。SQL 注入:AI 偶尔会用字符串拼接 SQL(尤其是复杂查询),必须用参数化查询/预编译语句。并发竞态:AI 写「扣库存」时可能先 SELECT 查库存再 UPDATE 扣减,两个请求同时查都看到 10 件,都扣 1 件,结果库存变成 9 但卖了 2 件(超卖)。应该用原子操作(UPDATE ... SET stock = stock - 1 WHERE stock > 0)或乐观锁。错误处理不完整:AI 可能只处理成功路径,忽略数据库连接失败、超时、第三方 API 失败等异常,导致进程崩溃或返回不明确错误。必须所有异步操作都 try/catch,返回统一错误格式。

第五步:用 AI 生成测试

测试是后端质量的保障。AI生成代码后,让AI同时生成测试用例。测试分三层:单元测试(测试单个函数/工具的逻辑,如密码哈希、Token生成、输入验证);集成测试(测试API接口的完整流程,发请求→查数据库→验证响应,用测试数据库);端到端测试(测试完整的用户流程,如注册→登录→创建课程→学习→答题)。

Python
// 让 AI 生成测试的提示词示例
// """
// 你是一个有 10 年经验的测试工程师,精通 Jest + Supertest + TypeScript。
// 
// 请为以下 API 接口编写完整的集成测试(参考已有的 user.test.ts 的风格):
// 
// 接口:POST /api/v1/courses(创建课程,仅管理员)
// 
// 测试用例:
// 1. 正常流程:管理员登录→发送合法请求→201 Created→数据库有记录→返回正确的课程对象
// 2. 未登录:不携带 Token→401 Unauthorized
// 3. 普通用户:学习者角色登录→403 Forbidden
// 4. 参数缺失:不传 title→400 Bad Request→错误信息明确
// 5. 参数非法:title 超过100字符→400 Bad Request
// 6. 价格为负数:price=-10→400 Bad Request
// 7. 重复创建:相同 title 创建两次→应该允许(title 不唯一)或按设计处理
// 
// 要求:
// - 用 Jest + Supertest
// - 每个测试前清理测试数据库(beforeEach)
// - 测试之间互不影响(用不同的测试数据)
// - 断言要充分(状态码、响应体字段、数据库记录)
// - 用工厂函数生成测试数据(如 createTestUser()、createTestAdmin())
// - 代码有中文注释
// """
print("让 AI 生成测试,覆盖正常/异常/边界场景,跑通所有测试才算完成")
🐍测试的价值和误区

测试的价值:防止回归——改了旧代码不破坏新功能;文档——测试用例是最好的接口文档;重构信心——有测试敢重构;强制好设计——难测试的代码通常设计不好。误区:追求100%覆盖率——覆盖率高不代表测试质量高,关键路径覆盖比数字重要;只测正常路径——不测异常和边界,Bug都出在那里;测试和实现耦合——测试只验证行为不验证实现细节,否则重构就要重写测试;测试太慢——集成测试用真实数据库但要快,用内存数据库或事务回滚,每个测试在事务里,结束回滚;不维护测试——测试失败了就注释掉,这是最危险的,测试必须始终通过。AI生成测试后,你要审查测试是否真的在验证行为、有没有覆盖异常场景、测试之间是否独立。

第六步:用 AI 调试后端 Bug

后端 Bug 比前端难调试——因为涉及数据库、网络、并发、状态,问题可能不在你改的那行代码。用 AI 调试的正确方法是:给 AI 看完整的报错信息(堆栈跟踪,不要只给最后一行);相关的代码(出错的函数、调用它的地方、相关的 Schema);上下文(什么操作触发的、预期结果是什么、实际结果是什么、能不能复现);你已经尝试过的排查(避免 AI 重复你已经做过的)。然后让 AI 分析根因、给出修复方案。

Python
// 用 AI 调试 Bug 的提示词示例
// """
// 你是一个有 10 年经验的后端调试专家,精通 Node.js + PostgreSQL + Prisma。
// 
// 问题描述:
// 用户反馈「创建课程时偶尔会失败,提示 'Internal Server Error',但重试一次就成功了」。
// 这个问题不是每次都出现,大约 10 次里有 1 次。
// 
// 报错信息(完整堆栈):
// Error: Invalid `prisma.course.create()` invocation in
// /app/src/controllers/course.controller.ts:45:32
//   Unique constraint failed on the fields: (`id`)
//   at ... (堆栈省略)
// 
// 相关代码(course.controller.ts 创建课程的部分):
// [粘贴完整的创建课程函数代码]
// 
// Schema(Prisma):
// model Course {
//   id        BigInt   @id @default(autoincrement())
//   title     String
//   ...
// }
// 
// 我已经尝试过的:
// - 检查了请求参数,没有问题
// - 数据库连接正常
// - 不是每次都出现,偶尔出现
// 
// 请分析:
// 1. 根因是什么?(为什么 id 会冲突?autoincrement 不应该冲突啊)
// 2. 为什么偶尔出现而不是每次?
// 3. 怎么修复?
// 4. 怎么防止类似问题?
// """
print("给 AI 完整报错+相关代码+上下文+已尝试排查,它能精准定位根因")
💡调试的通用方法论

能复现吗?——不能稳定复现的Bug最难修,先想办法稳定复现(加日志、构造特定数据、并发测试);看日志——后端一定要有详细的日志(请求ID、用户ID、操作、耗时、错误堆栈),用请求ID串联一次请求的所有日志;二分法——注释掉一半代码看Bug还在不在,逐步缩小范围;查数据库——很多Bug是数据问题(脏数据、约束违反、关联缺失),直接查数据库看数据状态;看并发——偶尔出现的Bug大概率是并发问题(竞态条件、死锁、连接池耗尽);加监控——APM工具(Sentry/New Relic/阿里云ARMS)能自动捕获异常和性能瓶颈;不要猜——用证据说话,加日志、加断点、查数据,不要「我觉得是这个原因」就改代码。AI可以帮你分析,但你要提供足够的证据(日志、数据、代码)。

本节小结

AI 写后端六步:设计数据模型(ER 图+Schema,AI 辅助生成,你审查字段类型/索引/约束/关联);设计 API 契约(URL/方法/参数/响应/错误码,前后端对齐);让 AI 实现(给技术栈+契约+Schema+已有代码风格,一次实现几个接口);审查安全和性能(SQL 注入/XSS/输入验证/错误处理/事务/N+1/索引/并发/敏感信息/日志,十项审查清单);生成和运行测试(单元+集成+E2E,覆盖正常/异常/边界,Jest+Supertest,测试独立不耦合);部署和监控(日志+APM+告警,用真实流量验证)。数据库迁移用 Prisma/Alembic/Flyway,每次变更有 up/down 脚本,进版本控制,生产大表变更小心锁表。AI 后端代码五个高频陷阱:N+1 查询、事务缺失、SQL 注入、并发竞态、错误处理不完整。调试方法论:能复现→看日志→二分法→查数据库→查并发→加监控→不要猜用证据。接下来讲 AI 能力集成——后端做好了,怎么给产品加上 AI 能力。

资深工程师加餐

底层原理 · 大厂视角 · 工程经验,点卡片展开

独立开发者选栈的第一标准是“能不能一个人最快稳定交付”,而不是哪个框架最新。Next.js 这类全栈框架把路由、构建、静态导出、服务端接口收敛到一套工具链里,配合静态导出 + WebView 原生壳,能让一个人同时覆盖 Web 与移动端;选型时先验证最不确定的环节(离线运行、原生能力、AI 流式),跑通原型再全面投入,避免做到一半发现关键能力不成立。