Chapter 09

与框架集成

在 Next.js、Express、NestJS 里正确使用单例 PrismaClient,理解连接池与 Serverless/Edge 部署的坑与解法。

9.1 核心概念

单例 PrismaClient
整个进程只应有一个 PrismaClient 实例。多实例各建连接池,快速耗尽数据库连接数。
热重载连接泄漏
开发时 Next.js/Nodemon 频繁热重载模块,若每次都 new PrismaClient() 会不断累积实例。用挂到 globalThis 的方式复用。
连接池(connection pool)
Prisma 维护一组到数据库的复用连接,池大小由连接串的 connection_limit 控制,默认与 CPU 相关。
Serverless 连接风暴
Lambda/函数每次冷启动新建连接,高并发时瞬间打爆数据库连接数。需外部连接池(PgBouncer)或 Accelerate。
Prisma Accelerate
官方托管的全球连接池 + 查询缓存层,通过 prisma:// 连接,缓解 Serverless 连接风暴并加速边缘读取。
driverAdapters
让 Prisma 用 JS 原生驱动(如 @prisma/adapter-neon@prisma/adapter-pg)走 WASM 引擎,支持 Cloudflare Workers/Vercel Edge 等边缘环境。

9.2 单例封装(通用 + Next.js)

// lib/prisma.ts —— 兼容开发热重载的单例
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };

export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({ log: ["query", "warn", "error"] });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

9.3 Next.js App Router

// app/users/page.tsx —— Server Component 直接查
import { prisma } from "@/lib/prisma";

export default async function Page() {
  const users = await prisma.user.findMany({ take: 20 });
  return <ul>{users.map((u) => <li key={u.id}>{u.email}</li>)}</ul>;
}
Prisma 不进浏览器

Prisma Client 只能在服务端运行(Server Component / Route Handler / Server Action)。别在 "use client" 组件里 import,会打包失败或泄漏连接串。

9.4 Express 集成

import express from "express";
import { prisma } from "./lib/prisma";

const app = express();
app.get("/users/:id", async (req, res) => {
  const user = await prisma.user.findUnique({ where: { id: Number(req.params.id) } });
  if (!user) return res.status(404).json({ error: "Not found" });
  res.json(user);
});

// 优雅关闭:进程退出前断开
process.on("beforeExit", () => prisma.$disconnect());

9.5 NestJS 集成

// prisma.service.ts
import { Injectable, OnModuleInit } from "@nestjs/common";
import { PrismaClient } from "@prisma/client";

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }
}

PrismaService 作为 provider 注入各 service,Nest 的 DI 天然保证单例。

9.6 Serverless 与连接池

# 直连数据库时限制连接数(配合外部 PgBouncer)
DATABASE_URL="postgresql://u:p@host:5432/db?connection_limit=1&pgbouncer=true"
部署形态推荐做法
长驻服务(VM/容器)单例 + 合理 connection_limit
Serverless 函数PgBouncer / Accelerate,connection_limit=1
Edge(Workers/Vercel Edge)driverAdapters + Accelerate(prisma://)

9.7 Edge:driverAdapter 示例

import { PrismaClient } from "@prisma/client";
import { PrismaNeon } from "@prisma/adapter-neon";

const adapter = new PrismaNeon({ connectionString: process.env.DATABASE_URL });
export const prisma = new PrismaClient({ adapter });
版本敏感

driverAdapters、Accelerate 的 API 与 preview flag 随版本演进较快。落地前请对照你所用 Prisma 版本的官方文档确认包名与配置。

9.8 小结与下一步