Next.js Serverless 数据库连接边界
解释 Next.js 托管函数环境下数据库连接池、实例并发、连接预算和 server-only data layer 的边界,避免把传统长驻服务连接模型原样搬进 serverless。
#synthesis
#growing
#backend
#database
#react
[!info] related notes
- 所属 MOC: nextjs-moc
- 相关概念:
- 易混淆概念:
- 相关资源:
Next.js Serverless 数据库连接边界
为什么 Next.js 需要单独理解数据库连接
在传统单进程后端中,常见模型是:
1 process
→ 1 connection pool
→ many requests reuse it
在托管函数环境中,平台可能同时存在多个实例:
instance A → pool
instance B → pool
instance C → pool
...
真正需要控制的是:
总连接数 ≈ 活跃实例数 × 每实例 pool 上限
如果每个实例都创建很大的连接池,数据库很容易先耗尽连接,而不是 CPU。
Server-only Data Layer
数据库 client、连接串和 Repository 应位于 server-only 模块:
Server Component / Server Action / Route Handler
↓
Data / Service Layer
↓
Drizzle
↓
PostgreSQL
不要把数据库驱动或连接凭证引入 Client Component 图。
Server Component 能访问数据库,只说明运行环境允许;是否应该直接访问仍取决于数据 ownership:
Next.js owns domain/data
→ 可经 server-only data layer 访问 DB
独立 Go/Java/Python service owns domain
→ Next.js 调 owning service API
→ 不绕过它直接写库
连接复用原则
常见做法是在模块作用域创建 client / pool,让同一运行实例的多个 invocation 复用它:
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: SMALL_LIMIT,
})
关键不是具体数字,而是容量预算:
DB max connections
- admin / migration reserve
- background workers
- other services
= Web 可使用连接预算
再把这份预算分配给可能并发存在的函数实例。
Driver 选择也是运行时问题
PostgreSQL 可以通过不同 driver 访问:
- TCP driver(如
pg/ postgres.js) - 平台提供的 serverless HTTP/WebSocket driver
- 外部 pooler / proxy
选择依据包括:
是否支持当前 runtime 网络能力
是否需要 transaction/session affinity
是否需要 prepared statement
连接创建成本
数据库连接限制
因此“ORM 一样”不代表连接模型一样。
常见错误
每个请求 new 一个完整连接池
会失去复用并快速制造连接抖动。
认为 module singleton 是全局 singleton
模块级变量通常只能保证当前实例内复用,不能保证整个部署只有一个实例。
用内存变量保存数据库业务状态
函数实例可能被回收;进程内状态不是 durable truth。
把连接池问题误认为 ORM 问题
Drizzle、Prisma、Kysely 等上层工具最终仍依赖 driver 和数据库连接模型。ORM 不会自动消除底层连接上限。
与缓存的区别
Connection Pool
→ 复用数据库连接资源
Next.js Cache
→ 复用查询/渲染结果
Database
→ authoritative durable state
减少查询次数和减少建连次数是两个不同优化维度。
最短记忆
serverless ≠ no server
serverless = server lifecycle owned by platform
module-level pool
= per-instance reusable resource
≠ globally unique pool
ORM
≠ connection management disappears
这篇笔记是 Part 14 中 Vercel、Drizzle 与数据库章节之间的桥梁。