05. 数据库集成与 ORM 最佳实践

在 Next.js 全栈开发中,数据库连接与传统的 Node.js 服务(如 Express 常驻内存)完全不同。

由于 Next.js API Routes 和 Server Actions 经常运行在 Serverless (无服务器) 环境中,函数执行完就会销毁。如果每次请求都创建一个新的数据库连接,高并发下会瞬间耗尽数据库连接数,导致应用崩溃。


1. 核心问题:连接池耗尽 (Connection Exhaustion)

❌ 错误写法:

// lib/db.ts
import { PrismaClient } from '@prisma/client'
 
// 😱 每次 import 这个文件,都会 new 一个新的连接实例
// 在开发环境(热更新)或 Serverless 环境下,这会导致连接数无限增长
export const db = new PrismaClient()

✅ 正确写法:全局单例模式

我们需要把客户端实例挂载到 globalThis 对象上,确保整个进程只存在一个实例。

// lib/db.ts
import { PrismaClient } from '@prisma/client'
 
// 1. 声明全局类型,防止 TS 报错
const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined
}
 
// 2. 如果已有实例则复用,否则新建
export const db = globalForPrisma.prisma ?? new PrismaClient()
 
// 3. 在非生产环境下,将实例保存到全局变量
if (process.env.NODE_ENV !== 'production') {
  globalForPrisma.prisma = db
}

这样,无论 Next.js 在开发环境怎么热重载 (Hot Reload),数据库连接始终只有一个。


2. ORM 选型建议

在 2024/2025 年,Next.js 生态主要流行两个 ORM:

特性PrismaDrizzle ORM
风格面向对象,Schema 优先 (schema.prisma)函数式,TS 代码优先
类型安全⭐️⭐️⭐️⭐️⭐️ (自动生成)⭐️⭐️⭐️⭐️⭐️ (基于 TS 推断)
性能⚠️ 较重 (基于 Rust Binary)🚀 极轻 (SQL wrapper)
冷启动较慢极快 (适合 Serverless)
适用场景传统企业级项目,快速开发,不极致追求冷启动速度Serverless Edge 环境,追求极致性能

Prisma 快速上手示例

  1. 安装

    npm install prisma --save-dev
    npm install @prisma/client
    npx prisma init
  2. 定义模型 (prisma/schema.prisma)

    model User {
      id    String @id @default(cuid())
      email String @unique
      posts Post[]
    }
     
    model Post {
      id        String  @id @default(cuid())
      title     String
      published Boolean @default(false)
      authorId  String
      author    User    @relation(fields: [authorId], references: [id])
    }
  3. 同步数据库

    npx prisma db push
  4. 在 Server Component 中使用

    // app/page.tsx
    import { db } from '@/lib/db'
     
    export default async function Page() {
      const posts = await db.post.findMany({
        where: { published: true },
        include: { author: true }
      })
     
      return (
        <ul>
          {posts.map(post => (
            <li key={post.id}>{post.title} by {post.author.email}</li>
          ))}
        </ul>
      )
    }

3. Serverless 环境下的特殊处理

如果你的数据库(如 MySQL/PostgreSQL)托管在传统云服务器上,而 Next.js 部署在 Vercel Edge 或 AWS Lambda 上,你需要使用 连接池代理 (Connection Pooling)

  • Vercel Postgres / Neon: 自带 Serverless Driver,无需担心。
  • PlanetScale: 使用 HTTP 协议,无连接数限制。
  • AWS RDS / 自建数据库: 必须配合 Prisma Data ProxyPgBouncer 使用,否则并发一高就会挂。

4. 总结

  1. 必须使用单例模式:防止开发环境和 Serverless 环境连接泄露。
  2. Server Component 直连:在 Server Component 中直接查数据库是最高效的,不需要经过 fetch API。
  3. 注意环境限制:如果部署在 Edge Runtime,Prisma 可能不兼容(因为它依赖 Node.js API),此时推荐用 Drizzle 或 Prisma Accelerate。