Skip to content
返回构建教程

数据库搭建

搭建 Postgres 带迁移、种子和连接池,用于本地 + prod。

为什么

数据库是最难后改的基础——其他层可重写,但迁移活数据是多天操作带真实风险。第一天设迁移意味着每 schema 变更被评审、版本化、可逆。种子给每开发者相同起始数据,'在我机器上能跑'含数据状态。连接池防负载下经典'连接太多'崩溃,这是早期应用 #1 生产 DB 故障。搭建时做对这三花 2 小时;上线后修花 2 天停机。

何时使用

第一个持久化数据功能之前。约 2-3 小时。无状态应用(纯计算无 DB)可跳过。

如何做

1. prod 用托管 Postgres(Neon、Supabase、RDS),本地用 docker-compose
   - 永不在你管的 VM 上跑 prod Postgres——备份和补丁是已解问题
   - 本地:docker-compose 带 postgres:16 + healthcheck

2. 用 Prisma 或 Drizzle 作 ORM + 迁移工具
   - prisma migrate dev --name init 创建首个迁移
   - 提交 migrations/ 到 git——它们是 schema 的事实源

3. 创建种子脚本(prisma/seed.ts)插入确定性开发数据
   - 用稳定 ID(固定种子的 crypto.randomUUID)让测试可复现
   - 每新 DB 跑:prisma db seed

4. 用 PgBouncer 或托管提供方的 pooler 配连接池
   - 池大小设为并发请求数的 2-10 倍,非 100
   - serverless 用事务 pooler 模式(Neon、Supabase)

5. 加 /api/health 端点检查 DB 连通性
   - SELECT 1——失败则健康检查返回 503,负载均衡器排水

示例

// docker-compose.yml(本地 Postgres)
services:
  db:
    image: postgres:16
    environment: { POSTGRES_PASSWORD: dev, POSTGRES_DB: app }
    ports: ["5432:5432"]
    healthcheck: { test: ["CMD-SHELL", "pg_isready"], interval: "5s" }

// prisma/seed.ts
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
await prisma.user.upsert({
  where: { email: "[email protected]" },
  create: { email: "[email protected]", role: "ADMIN" },
  update: {},
});

// 健康检查
export async function GET() {
  try { await prisma.$queryRaw`SELECT 1`; return new Response("ok"); }
  catch { return new Response("DB 宕", { status: 503 }); }
}

常见问题

  • ⚠部署步骤里跑迁移而非单独门控步骤,迁移失败阻塞部署。
  • ⚠不种子 DB,每开发者数据不同,bug 不可复现。
  • ⚠serverless 每请求开新 Prisma 客户端,秒级耗尽连接池。
  • ⚠prod 用 prisma db push 而非 prisma migrate deploy,丢迁移历史和回滚能力。

最佳实践

  • ✓预部署步骤带维护页跑迁移,非滚动部署期间——零停机迁移仅加性变更可行。
  • ✓serverless 用全局 Prisma 客户端单例(globalThis.prisma)跨调用复用连接。
  • ✓迁移写加性(加列、加表)分两阶段部署——先后向兼容再破坏性变更。
  • ✓每 prod 迁移前备份 DB(pg_dump 或提供方快照)——30 秒备份省 3 小时恢复。