06.1
存储选型
强一致、关系复杂、需要事务 → 关系型(PostgreSQL/MySQL);schema 灵活、写入量大、文档结构 → MongoDB。原型期 SQLite 零配置。
| 场景 | 推荐 |
|---|---|
| 事务/强一致/报表 | PostgreSQL |
| 快速原型/单机 | SQLite |
| 灵活 schema/日志/画像 | MongoDB |
06.2
原生驱动
直接用 pg(PostgreSQL)等驱动可完全控制 SQL,适合复杂查询与极致性能。
import pg from 'pg';
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
const { rows } = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
console.log(rows);参数化查询
永远用 $1, $2 占位符,不要字符串拼接 SQL,杜绝注入。
06.3
Prisma ORM
Prisma 用 schema 声明模型,自动生成类型安全的客户端与迁移,开发体验极佳。
// schema.prisma
model User {
id Int @id @default(autoincrement())
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id])
authorId Int
}import { PrismaClient } from '@prisma/client';
const db = new PrismaClient();
const user = await db.user.findUnique({
where: { email: 'a@b.com' },
include: { posts: true }
});06.4
连接池
每个请求都新建数据库连接代价高。连接池复用连接;注意上限,避免超过数据库 max_connections。
// 全局单例,不要每个请求 new 一个
const pool = new pg.Pool({ max: 10 });
// Serverless 环境用完要结束,否则进程不退出
process.on('SIGTERM', () => pool.end());池耗尽可能性
请求里忘记释放连接(未 await 或异常路径未关)会耗尽池,导致后续请求全部挂起。用 ORM 或 try/finally 保证释放。
06.5
事务
多个写操作要么全成要么全败,用事务包裹。Prisma 提供 $transaction,原生驱动用 BEGIN/COMMIT。
const result = await db.$transaction(async (tx) => {
const order = await tx.order.create({ data: { total } });
await tx.stock.update({
where: { id: sku },
data: { qty: { decrement: 1 } }
});
return order; // 任一抛错自动回滚
});06.6
迁移与种子
迁移把 schema 变更纳入版本管理;种子初始化基础数据。两者都应可重放、可回滚。
npx prisma migrate dev --name init # 生成并执行迁移
npx prisma db seed # 灌入种子数据06.7
MongoDB 文档库
Mongoose 提供 schema 建模与校验;原生 mongodb 驱动更轻。适合嵌套结构、灵活字段。
import mongoose from 'mongoose';
await mongoose.connect(process.env.MONGO_URL);
const User = mongoose.model('User', new mongoose.Schema({
email: { type: String, required: true, unique: true }
}));
await User.create({ email: 'a@b.com' });06.8
常见陷阱与 FAQ
没有银弹。通常每实例 10–20,乘以实例数不超过数据库 max_connections。先小再观测调大。
业务 CRUD 用 ORM 提效、保证类型安全;复杂报表/批量用原生 SQL 控制执行计划。两者可共存。
大表加字段/索引要锁表,应在低峰期用 CONCURRENTLY 等在线手段,并在 CI 演练。
06.9