ORM 干什么

数据库表 ↔ JS / TS 对象的转换层 + 类型安全 + 迁移管理。

主流:

ORM 风格 特点
Prisma Schema 文件 + 生成 client 最受欢迎、文档好、TS 一等公民
Drizzle TypeScript schema 更轻量、类似 SQL 的链式 API
TypeORM 装饰器 + 类 老牌、Java 风
Sequelize model 定义 Express 时代最流行
Knex Query Builder(不算完整 ORM) 灵活、低层

新项目 TS 推荐 Prisma 或 Drizzle

Prisma

npm install -D prisma
npm install @prisma/client
npx prisma init

Schema 文件(schema.prisma)

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String
  age       Int?
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  content  String?
  authorId Int
  author   User   @relation(fields: [authorId], references: [id])
}

迁移 + 生成 client

npx prisma migrate dev --name init      # 建迁移 + 应用
npx prisma generate                      # 生成 TS client

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

// 创建
const user = await prisma.user.create({
    data: { email: 'a@x.com', name: 'Alice' },
});

// 查询
const users = await prisma.user.findMany({
    where: { age: { gte: 18 } },
    orderBy: { name: 'asc' },
    take: 20,
});

// 关联(include / select)
const userWithPosts = await prisma.user.findUnique({
    where: { id: 1 },
    include: { posts: true },
});

// 更新
await prisma.user.update({
    where: { id: 1 },
    data: { age: 31 },
});

// 删除
await prisma.user.delete({ where: { id: 1 } });

// 事务
await prisma.$transaction(async (tx) => {
    await tx.user.update({ ... });
    await tx.post.create({ ... });
});

// 原生 SQL
const rows = await prisma.$queryRaw`SELECT * FROM users WHERE id = ${42}`;

所有方法返回值都有完整 TS 类型——这是 Prisma 最大卖点。

Drizzle

npm install drizzle-orm
npm install -D drizzle-kit

Schema(TS)

import { pgTable, serial, varchar, integer } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
    id: serial('id').primaryKey(),
    email: varchar('email', { length: 255 }).unique().notNull(),
    name: varchar('name', { length: 100 }).notNull(),
    age: integer('age'),
});

export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    title: varchar('title').notNull(),
    authorId: integer('author_id').references(() => users.id),
});

import { drizzle } from 'drizzle-orm/postgres-js';
import { eq, gte, and } from 'drizzle-orm';
import postgres from 'postgres';
import { users, posts } from './schema';

const sql = postgres(process.env.DATABASE_URL);
const db = drizzle(sql);

// 插入
const [user] = await db.insert(users).values({
    email: 'a@x.com', name: 'Alice', age: 30,
}).returning();

// 查
const list = await db.select().from(users).where(gte(users.age, 18));

// 关联
const withPosts = await db
    .select()
    .from(users)
    .leftJoin(posts, eq(users.id, posts.authorId));

// 更新
await db.update(users).set({ age: 31 }).where(eq(users.id, 1));

// 删
await db.delete(users).where(eq(users.id, 1));

// 事务
await db.transaction(async (tx) => {
    await tx.insert(users).values({ ... });
    await tx.insert(posts).values({ ... });
});

Drizzle 风格更贴近 SQL——查询能力强、生成的 SQL 更可预测。

Prisma vs Drizzle

维度 Prisma Drizzle
类型安全 ★★★★★ ★★★★★
Schema 形式 单独 DSL 文件 TS 代码
学习曲线
性能 (生成 SQL 直接,无 runtime overhead)
复杂查询 较弱(用 raw 补) 强(接近 SQL)
迁移 内置 内置
Bundle 大小 较大
生态 增长中

简单项目用 Prisma(更友好),复杂 SQL / 性能敏感用 Drizzle

迁移

# Prisma
npx prisma migrate dev --name add_user_age      # 开发
npx prisma migrate deploy                         # 生产部署

# Drizzle
npx drizzle-kit generate                          # 生成迁移
npx drizzle-kit migrate                           # 应用

何时不用 ORM

  • 极简项目(直接 SQL 更快)
  • 极致性能(ORM 总有些开销)
  • 复杂分析查询(ORM 翻译易出错)

这些场景用原生 pg / postgres.js + 手写 SQL 更直接。

  • ORM 生成的 SQL 不总是最优——慢查询要 EXPLAIN ANALYZE
  • N+1 查询陷阱(每个对象单独查一次关联)—— 用 include / join
  • 字段名 vs 列名容易混淆——schema 里定义清楚
  • 迁移生产前必须演练——schema 改动可能锁表

下一篇:测试。