告别臃肿:为什么 Drizzle ORM 是 TypeScript 后端的未来?

1. 引言:我们受够了"黑盒"魔法

作为一名后端开发者,你一定有过这样的崩溃时刻:

你正在使用某个主流 ORM(比如 TypeORM 或 Prisma)。起初,一切都很美好,User.findMany() 跑得很欢。但随着业务变复杂,你发现:

  1. 性能黑洞:一个简单的查询,ORM 居然生成了 50 行极其低效的 SQL Join 语句。

  2. 启动龟速:在 Serverless 环境下(如 AWS Lambda),ORM 庞大的运行时让冷启动时间慢得像蜗牛。

  3. 调试噩梦:报错信息像天书,你根本不知道 ORM 底层到底对数据库做了什么。

你开始怀念手写 SQL 的日子------极速、精准、完全可控。但手写 SQL 又让你失去了 TypeScript 的类型提示,还得手动拼接字符串,不仅累还容易注入 SQL。

如果有一种工具,既能让你像写 SQL 一样思考,又能拥有 TypeScript 的极致类型安全,还几乎没有运行时开销,你会心动吗?

这,就是 Drizzle ORM


2. 概念拆解:如果你懂 SQL,你就懂 Drizzle

2.1 生活化类比:翻译机 vs. 智能纠错笔

为了理解 Drizzle 和传统 ORM 的区别,我们来打个比方:

  • 传统 ORM (Prisma/TypeORM) 就像一台"万能翻译机" : 你说:"我要一份宫保鸡丁"。翻译机可能会在厨房里一番操作,最后给你端出来一份菜。但你不知道它加了多少盐,是不是用了预制菜。它把厨房(数据库)完全屏蔽了,你虽然省心,但失去了控制权

  • Drizzle ORM 就像一支"智能语法纠错笔" : 你依然是主厨,你需要自己决定"先切肉,再热油"(编写查询逻辑)。但是,Drizzle 这支笔会在你写菜谱时实时告诉你:"嘿,这里少加了糖"或者"这种肉不能搭配这种酱汁"(类型检查)。

    核心理念:Drizzle 只有一层极薄的抽象。它不会隐藏 SQL,它只是用 TypeScript 的语法"拥抱"了 SQL。

2.2 核心工作流图解

如果无法查看图片,请想象以下层级结构:

  1. TypeScript Schema: 你用 TS 定义表结构(这是唯一的真理源头)。

  2. Drizzle Logic : 你调用 Drizzle 的方法(如 .select().from()),这些方法与标准 SQL 关键词一一对应。

  3. SQL Output : Drizzle 瞬间将其转换为纯净的 SQL 字符串,零多余逻辑

  4. Database: 执行查询。


3. 动手实战:三分钟上手 Drizzle

我们将构建一个极简的"用户-文章"系统。为了方便演示,我们使用 SQLite(但在 Postgres 或 MySQL 上体验几乎一致)。

第一步:安装依赖

Bash

复制代码
npm install drizzle-orm better-sqlite3
npm install -D drizzle-kit @types/better-sqlite3

第二步:定义 Schema(真理之源)

在 Drizzle 中,你的 TS 代码就是数据库结构。
TypeScript

复制代码
// schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';

// 定义 Users 表
export const users = sqliteTable('users', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  fullName: text('full_name'), // 映射到数据库的 'full_name' 字段
  isPro: integer('is_pro', { mode: 'boolean' }).default(false), // 自动处理 boolean 转换
});

// 定义 Posts 表
export const posts = sqliteTable('posts', {
  id: integer('id').primaryKey({ autoIncrement: true }),
  title: text('title').notNull(),
  authorId: integer('author_id').references(() => users.id), // 外键关联
});

第三步:连接与写入 (Hello World)

TypeScript

复制代码
// index.ts
import { drizzle } from 'drizzle-orm/better-sqlite3';
import Database from 'better-sqlite3';
import { users, posts } from './schema';
import { eq } from 'drizzle-orm';

// 1. 初始化数据库连接
const sqlite = new Database('sqlite.db');
const db = drizzle(sqlite);

async function main() {
  // 模拟迁移(实际项目中请使用 drizzle-kit push)
  sqlite.exec(`
    CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, full_name TEXT, is_pro INTEGER);
    CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author_id INTEGER);
  `);

  console.log('Inserting data...');

  // 2. 插入数据 - 看起来非常像 SQL
  // INSERT INTO users (full_name, is_pro) VALUES ('Tony Stark', true) RETURNING *;
  const newUser = await db.insert(users)
    .values({
      fullName: 'Tony Stark',
      isPro: true,
    })
    .returning(); // Drizzle 特性:直接返回插入后的数据

  console.log('Created User:', newUser);

  // 3. 关联插入
  await db.insert(posts).values({
    title: 'How to build an Iron Man suit',
    authorId: newUser[0].id,
  });
}

main();

第四步:查询数据 (The "Why")

这就是 Drizzle 发光的地方。看这个查询,它既是 SQL 又是 TS。
TypeScript

复制代码
// ... 上接 index.ts

async function queryData() {
  // SELECT * FROM users WHERE is_pro = 1;
  const proUsers = await db.select()
    .from(users)
    .where(eq(users.isPro, true)); // 使用 eq (equal) 运算符
    
  console.log('Pro Users:', proUsers);
  // 这里的 proUsers 类型被完美推导为:
  // { id: number; fullName: string | null; isPro: boolean | null }[]
}

解析:

  • db.select().from(users): 这不是什么黑魔法 API,这读起来就是 SQL。

  • eq(users.isPro, true): Drizzle 提供了完整的 SQL 运算符封装(eq, gt, like, and, or 等),确保你不会拼错 SQL 语法。


4. 进阶深潜:关系查询与最佳实践

痛点:Join 很难写?

在传统 ORM 中,关联查询(Relation)往往很隐晦。Drizzle 提供了两种模式:SQL 模式查询构建器模式 (Relational Queries)

模式一:SQL Like (硬核模式)

如果你擅长 SQL,想精确控制 Join:
TypeScript

复制代码
const result = await db.select()
  .from(users)
  .leftJoin(posts, eq(users.id, posts.authorId)) // 显式 Left Join
  .where(eq(users.id, 1));

优势:你知道每一个 Join 是如何发生的,性能完全可控。

模式二:Drizzle Queries (Prisma 风格)

如果你想要类似 Prisma 的嵌套查询体验,Drizzle 也支持(且性能更好):
TypeScript

复制代码
// 需要先在 schema 中定义 relations (略)
const result = await db.query.users.findMany({
  with: {
    posts: true // 自动把帖子带出来
  }
});

最佳实践建议

  1. 一定要用 Drizzle Kit : 不要手动写 SQL 建表。使用 drizzle-kit 命令行工具,它可以根据你的 schema.ts 自动生成 SQL 迁移文件(Migration files)。

    命令:npx drizzle-kit generate:sqlite

  2. Serverless 的首选: 由于 Drizzle 没有复杂的运行时对象映射,它的体积极小,且支持 Edge 环境(如 Cloudflare Workers)。如果你的业务在 Edge 上,Drizzle 几乎是唯一选择。

  3. 分离类型定义: 你可以利用 Drizzle 提供的工具从 schema 中推导出 TS 类型,用于前端传参校验:

    TypeScript

    复制代码
    import { type InferSelectModel } from 'drizzle-orm';
    type User = InferSelectModel<typeof users>; // 自动获得 User 类型

5. 总结与延伸

一句话总结 : Drizzle ORM 不是为了替代 SQL,而是为了让 TypeScript 开发者能以类型安全零开销 的方式,重新找回对数据库的掌控权

🚀 下一步 (Next Step)

立刻动手 : 不要只看不练。请打开你的编辑器,创建一个新文件夹,试着把你自己项目中的一个复杂 SQL 查询(包含 Join 的那种),用 Drizzle 的 select().from().leftJoin() 语法重写一遍

你会惊讶地发现,原来在 TypeScript 里写 SQL 可以这么丝滑。

相关推荐
濮水大叔14 小时前
在大型 Vue 项目中,如何有效管理复杂的状态?“散装版” vs “套装版”
前端·vue.js·typescript
谷哥的小弟2 天前
TypeScript数组类型
javascript·typescript
退休倒计时2 天前
【每日一题】LeetCode 199. 二叉树的右视图 TypeScript
算法·leetcode·typescript
前端之虎陈随易2 天前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
后台开发者Ethan3 天前
类型分类、联合类型、交叉类型
typescript
鹰影473 天前
一款AI笔记助手和远程同步的markdown笔记idea-note
人工智能·笔记·rust·typescript·react
想你依然心痛3 天前
AtomCode 在前端开发中的实战体验:React + TypeScript 项目开发实录
前端·react.js·typescript
疯狂的魔鬼3 天前
精确计算容器剩余视口高度:useAutoContainerFullHeight 的工程实践
前端·css·typescript
后台开发者Ethan3 天前
类型与变量
开发语言·typescript
孤狼warrior3 天前
从冒泡到传送带流水线:一个3D沉浸式算法靶场,让思想的伟力改变世界
python·算法·typescript