跳到主要内容

Drizzle

Prisma 和 Drizzle 在数据库操作方面采取了不同的方法。Drizzle 吸引那些偏好接近 SQL 编写查询的开发者,而 Prisma 则旨在支持构建和维护生产级应用程序的团队——在这些场景中,清晰性、协作和长期可维护性至关重要。

虽然这两个库解决的问题相似,但它们的工作方式截然不同,各有优缺点。选择哪个将取决于你的项目需求以及对项目重要的具体权衡。

Drizzle vs Prisma ORM

Drizzle 是一个传统的 SQL 查询构建器,允许你使用 JavaScript/TypeScript 函数来组合 SQL 查询。它既可以用于查询数据库,也可以用于运行迁移。Drizzle 还提供了一个查询 API (Queries API),它提供了比 SQL 更高层次的抽象,可用于读取嵌套关系。Drizzle schema 在 TypeScript 文件中定义,这些文件用于生成 SQL 迁移,然后针对数据库执行。

Prisma ORM 解决了传统 ORM 的许多问题,例如臃肿的模型实例、业务逻辑与存储逻辑混淆、缺乏类型安全或因懒加载等导致不可预测的查询。它使用 Prisma schema 以声明式方式定义应用程序模型。Prisma Migrate 允许从 Prisma schema 生成 SQL 迁移,并针对数据库执行。CRUD 查询由 Prisma Client 提供,这是一个轻量级且完全类型安全的 Node.js 和 TypeScript 数据库客户端。

Prisma:为团队打造

Prisma 旨在帮助团队更快地交付产品——尤其是在并非所有人都是 SQL 专家的情况下。

  • 无 SQL 瓶颈:使用 Prisma,你无需深厚的 SQL 知识即可高效工作。你的整个团队都可以为后端代码做出贡献——无需依赖某一个人编写原始查询或调试数据库逻辑。
  • 共享心智模型:Prisma 的 schema 易于阅读和理解。它提供了应用程序数据模型的单一、一致视图。
  • 更简单的代码审查:Schema 变更和数据访问模式透明且一致,使审查者更容易理解和批准后端更改。
  • 可预测的工作流:Prisma 自动化了迁移生成、客户端类型定义和查询构建——这样你的团队就不必手动完成这些工作。

Drizzle 在了解 SQL 或倾向于学习 SQL 的单个开发者手中可能非常棒。但一旦你有了团队,Prisma 就会消除阻碍你速度的摩擦和知识风险。

类型安全

Drizzle 并非完全类型安全。正如第三方进行的这项 比较研究中所述:“Drizzle 给人一种类型安全的印象。然而,只有查询结果具有类型信息。你可以使用 Drizzle 编写无效查询。”

借助 Prisma,由于生成的类型,你可以获得完全的类型安全。这意味着在编写代码和与团队成员协作时,出错的可能性更小。

Prisma Schema 作为单一事实来源

使用 Prisma,你的数据模型位于一个单一文件中:schema.prisma。

  • 显式化:无需推断类型或破译 SQL 生成函数——你的 schema 就在那里。
  • 可读性强:即使是非技术团队成员也能理解你的模型和关系。
  • 驱动一切:迁移、TypeScript 类型、自动补全、ERD 生成等都来自你的 schema。

相比之下,Drizzle 的 schema 是通过 TypeScript 代码构建的,这使得可视化完整的数据模型更加困难,增加了认知负荷,并可能导致跨代码库定义模型时出现不一致。阅读更多关于我们为何看好 PSL (Prisma Schema Language) 的内容。

想将你的 schema 查看为 ERD?使用 Prisma,只需一个命令:npx prisma generate && npx prisma-erd-generator

API 设计与抽象级别

Drizzle 和 Prisma ORM 在不同的抽象级别上运行。Drizzle 的理念是“如果你懂 SQL,你就懂 Drizzle ORM”。它的 API 模仿 SQL,而 Prisma Client 提供了一个更高级别的抽象,旨在满足应用程序开发人员的常见任务。Prisma ORM 的 API 设计强烈倾向于让正确的事情变得简单这一理念。

虽然 Prisma Client 在更高层次的抽象上运行,但你随时可以回退到原始 SQL。然而,充分使用 Prisma ORM 并开发你的应用程序不需要 SQL 知识。Prisma ORM 的目标是构建一种专注于开发者体验和生产力的查询语法,让开发者感到熟悉。你可以在这里了解更多信息:为何选择 Prisma

对于少数无法在 Prisma Client API 中表达的查询,Prisma ORM 还提供了 TypedSQL,通过直接利用 .sql 文件提供更熟悉和类型安全的体验。你现有的 SQL 工具和工作流可以与 Prisma Client 协同工作,以处理任何所需的抽象级别。

虽然 Prisma ORM 通过 TypedSQL 提供了完全类型化的 SQL 查询,但以下部分将探讨 Prisma 和 Drizzle API 的一些不同之处,以及 Prisma ORM 在这些情况下的 API 设计理念。

数据建模

Prisma 模型定义在 Prisma schema 中,而 Drizzle 使用 TypeScript 函数进行表定义。这些函数随后被导出并在查询中使用。

Prisma 生成一个轻量级的数据库客户端,它暴露了一个定制的、完全类型安全的 API,用于读取和写入在 Prisma schema 中定义的模型数据,遵循 DataMapper ORM 模式。

Prisma ORM 的数据建模 DSL 精简、简单且直观易用。在 VS Code 中建模数据时,你可以进一步利用 Prisma ORM 强大的 VS Code 扩展,它具有自动补全、快速修复、跳转到定义等功能,以及其他提高开发者生产力的优势。另一方面,Drizzle 使用 TypeScript 意味着你可以利用 TypeScript 的强大功能来实现额外的灵活性(例如,通过代码复用)。

Prisma ORM
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int?
author User? @relation(fields: [authorId], references: [id])
}
Drizzle
import {
boolean,
integer,
pgTable,
serial,
text,
uniqueIndex,
varchar,
} from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: varchar('name', { length: 256 }),
email: varchar('email', { length: 256 }).unique(),
})

export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: varchar('title', { length: 256 }).notNull(),
content: text('content'),
published: boolean('published'),
authorId: integer('author_id').references(() => users.id),
})

迁移

Drizzle 和 Prisma ORM 的迁移工作方式相似。两种工具都遵循根据提供的模型定义生成 SQL 文件的方法,并提供 CLI 以针对数据库执行这些文件。SQL 文件可以在执行迁移之前进行修改,以便使用任何一个迁移系统执行任何自定义数据库操作。

查询

在 Drizzle 和 Prisma ORM 中,构建普通查询都很自然。使用 Drizzle 的 Queries API,两种方法非常相似

Prisma ORM
// find all users
const allUsers = await prisma.user.findMany()

// find a single user
const user = await prisma.user.findFirst({
where: { id: 27 },
})

// find a unique user
const user = await prisma.user.findUnique({
where: { email: 'nilu@prisma.io' },
})
Drizzle
import { eq } from 'drizzle-orm'

// find all users
const allUsers = await db.query.users.findMany()

// find a single user
const user = await db.query.users.findFirst({
where: eq(users.id, 1),
})

// find a unique post
const user = await db.query.users.findFirst({
where: eq(users.email, 'nilu@prisma.io'),
})

当执行修改操作(createupdatedelete)时,Drizzle Queries API 不可用。在这些情况下,你需要使用 Drizzle 的类 SQL API。

Prisma ORM
// create a user
const user = await prisma.user.create({
data: {
name: 'Nilu',
email: 'nilu@prisma.io',
},
})

// update a user
const user = await prisma.user.update({
where: { email: 'nilu@prisma.io' },
data: { name: 'Another Nilu' },
})

// delete a user
const deletedUser = await prisma.user.delete({
where: { email: 'nilu@prisma.io' },
})
Drizzle
// create a user
const user = await db.insert(users).values({
name: 'Nilu',
email: 'nilu@prisma.io',
})

// update a user
const user = await db
.update(users)
.set({ name: 'Another Nilu' })
.where(eq(users.email, 'nilu@prisma.io'))
.returning()

// delete a user
const deletedUser = await db
.delete(users)
.where(eq(users.email, 'nilu@prisma.io'))
.returning()

关系

在 SQL 中,处理通过外键连接的记录可能会变得非常复杂。Prisma ORM 的虚拟关系字段概念为应用程序开发人员提供了直观便捷的方式来处理相关数据。Prisma ORM 方法的一些优点包括

  • 通过 fluent API 遍历关系(文档
  • 允许更新/创建关联记录的嵌套写入(文档
  • 对相关记录应用过滤器(文档
  • 轻松且类型安全地查询嵌套数据,无需担心底层 SQL(文档
  • 基于模型及其关系创建嵌套的 TypeScript 类型定义(文档
  • 通过关系字段在数据模型中直观地建模关系(文档
  • 隐式处理关系表(有时也称为 JOIN、link、pivot 或 junction 表)(文档
Prisma ORM
const posts = await prisma.post.findMany({
include: {
author: true,
},
})
Drizzle
const posts = await db.query.posts.findMany({
with: {
author: true,
},
})

过滤

Drizzle 公开给定 SQL 方言的底层过滤器和条件运算符。另一方面,Prisma ORM 提供了一组更通用且直观的运算符

Drizzle 和 Prisma ORM 的过滤 API 如何不同,一个很好的例子是查看 string 过滤器。Drizzle 提供了 likeilike 过滤器,而 Prisma ORM 提供了开发人员可以使用的更具体的运算符,例如:containsstartsWithendsWith

Prisma ORM
// case sensitive filter
const posts = await prisma.post.findMany({
where: {
title: 'Hello World',
},
})

// case insensitive filter
const posts = await prisma.post.findMany({
where: {
title: 'Hello World',
mode: 'insensitive',
},
})
Drizzle
// case sensitive filter
const posts = await db
.select()
.from(posts)
.where(like(posts.title, 'Hello World'))

// case insensitive filter
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, 'Hello World'))
Prisma ORM
const posts = await prisma.post.findMany({
where: {
title: {
contains: 'Hello World',
},
},
})
Drizzle
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, '%Hello World%'))
Prisma ORM
const posts = await prisma.post.findMany({
where: {
title: {
startsWith: 'Hello World',
},
},
})
Drizzle
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, 'Hello World%'))
Prisma ORM
const posts = await prisma.post.findMany({
where: {
title: {
endsWith: 'Hello World',
},
},
})
Drizzle
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, '%Hello World'))

可观测性

Drizzle 和 Prisma ORM 都能够记录查询及其生成的底层 SQL。

Prisma ORM 在客户端中内置了额外功能,帮助团队更好地理解其数据使用情况。指标追踪是两个可以随时启用并提供每个查询信息的特性。这些信息可以与外部工具集成,以便你可以跟踪随时间变化的性能。

附加产品

Drizzle 和 Prisma 都提供了与 ORM 配套的产品。Prisma Studio 的发布旨在允许用户通过 GUI 与数据库交互,并允许团队内部有限的自托管。Drizzle Studio 的发布旨在完成相同的任务。

除了 Prisma Studio,Prisma 还通过 Prisma 数据平台提供商业产品

  • Prisma Accelerate:一个连接池和全局缓存,与 Prisma ORM 集成。用户可以立即利用连接池,并可以在单个查询级别控制缓存。
  • Prisma Optimize:一个查询分析工具,提供深度洞察、可操作的建议,并允许你与 Prisma AI 交互以获取更多洞察并优化你的数据库查询。

这些产品与 Prisma ORM 协同工作,提供全面的数据工具,通过遵循数据 DX原则,使构建数据驱动型应用程序变得轻松。

更安全的变更和更少的缺陷

Prisma 最大限度地减少了在数据库操作中人为错误的风险。

  • 重命名字段?Prisma 会自动更新 schema、数据库和生成的客户端。你将自动保持同步。
  • 更改关系?Prisma 生成安全的迁移并通过完整的类型安全强制执行正确性。

团队选择 Prisma,因为它强制执行正确性,并帮助你快速前进而不会破坏现有功能。

开箱即用的生态系统

Drizzle 和 Prisma ORM 都存在用户希望执行库不直接支持的操作的情况。Drizzle 依赖 SQL 的表达能力来避免这些情况,而 Prisma ORM 则拥有Prisma Client 扩展,允许任何用户为其 Prisma Client 实例添加额外行为。这些扩展也是可共享的,这意味着团队可以开发它们以用于其项目,甚至供其他团队使用。

Drizzle 是一个相对较新的产品,而 Prisma ORM 于 2021 年发布,并在 JavaScript/TypeScript 领域稳固建立。它已证明其价值,许多公司在生产环境中信任 Prisma ORM

Prisma ORM 还被许多元框架和开发平台选为首选数据层工具,例如 AmplicationWaspRedwoodJSKeystoneJSRemixt3 stack

由于其成熟度,Prisma 社区已经开发了大量有用的工具,有助于各种 Prisma 工作流。以下是其中几个亮点

Prisma 不仅仅是一个 ORM——它是一个完整的类型安全数据工具包

  • Prisma Schema → 迁移、类型和文档
  • Prisma Client → 自动补全、完全类型安全的查询
  • Prisma Studio → 一个用于检查和编辑数据的 GUI
  • 原生集成 → PlanetScale、Vercel、Cloudflare D1、Neon 等

数据库支持

Drizzle 和 Prisma ORM 都支持多种不同类型的数据库。Drizzle 通过其创建的驱动程序实现来达到这种支持,这些驱动程序与现有的第三方数据库驱动程序集成。

Prisma ORM 已开始增加对第三方数据库驱动程序的支持,但主要使用内置驱动程序与底层数据库通信。Prisma 还将连接默认为 TLS,这提高了安全性。

此外,Prisma ORM 支持 CockroachDB、Microsoft SQL Server 和 MongoDB,而 Drizzle 目前不支持这些。Prisma ORM 还提供了关系模式,允许 Prisma ORM 为那些不支持外键约束的数据库引擎模拟外键约束。Drizzle 目前支持 Cloudflare D1、bun:sqlite 和通过 HTTP 代理的 SQLite,而 Prisma ORM 目前不支持这些。

基准测试

我们理解性能是选择 ORM 时的关键考量。为了比较各种 ORM 的性能,你可以使用 Vercel 托管的开源数据库延迟基准测试工具。这个工具允许你在不同工作负载和配置下评估各种 ORM 的延迟和吞吐量。通过针对你正在考虑的数据库或数据库提供商运行基准测试,你可以清楚地了解它们的相对性能特征,从而帮助做出明智的决定。

此外,你还可以查阅我们构建的基准测试工具上的发现,该工具比较了包括 Drizzle 在内的流行 TypeScript ORM。这个基准测试是开源的,旨在公平比较 Node.js 和 TypeScript 生态系统中数据库提供商和 ORM 库之间的数据库查询延迟。

结论

是的,我们有偏见,但这也是我们从用户和客户那里听到的反馈

  • “我们从 Drizzle 切换到 Prisma,因为 schema 漂移让我们苦不堪言。Prisma 就是好用。”
  • “多亏了 Prisma 的 schema,我在 2 小时内就让一名初级开发者上手了。如果用 Drizzle,可能要花几天时间。”
  • “我信任 Prisma 能让我们的数据库保持健康。我们团队中没有人需要成为 Postgres 专家。”
  • “Prisma 团队更新和新功能的推出速度简直令人惊叹。”

Drizzle ORM 和 Prisma ORM 都是用于数据访问和迁移的工具。Drizzle 专注于作为 SQL 风格语法的一个薄包装层,而 Prisma 则专注于提供便捷和富有表现力的 API。其他重要区别包括 Prisma ORM 对 MSSQL 和 MongoDB 的支持、通过Prisma Client 扩展支持附加功能、额外的云就绪产品以及一个健壮的生态系统。

另一方面,对于由具有不同数据库经验水平的开发者(前端、后端和全栈)组成的团队,Prisma ORM 为数据访问和数据库 schema 管理提供了一种全面且易于学习的方法。


与 Prisma 保持联系

通过以下方式继续你的 Prisma 之旅 我们活跃的社区。保持信息更新,参与其中,并与其他开发者协作

我们真诚地珍视你的参与,并期待你成为我们社区的一部分!

© . All rights reserved.