跳至主要内容

Drizzle

Prisma 和 Drizzle 在使用数据库方面采取了不同的方法。Drizzle 吸引了那些喜欢编写接近 SQL 语句的开发人员,而 Prisma 则旨在支持团队构建和维护生产应用程序,其中清晰度、协作和长期可维护性至关重要。

虽然这两个库解决了类似的问题,但它们的工作方式非常不同,并且各有优缺点。选择哪一个将取决于你的项目需求以及对项目而言重要的权衡。

Drizzle vs Prisma ORM

Drizzle 是一个传统的 SQL 查询构建器,允许你使用 JavaScript/TypeScript 函数编写 SQL 查询。它可以用于查询数据库或运行迁移。Drizzle 还提供了一个 Queries API,它提供了比 SQL 更高层次的抽象,可以用于读取嵌套关系。Drizzle 模式在 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 的目标是构建一个专注于开发人员体验和生产力的查询语法,让开发人员感到熟悉。你可以在这里了解更多信息:Why 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,用于按照 DataMapper ORM 模式读取和写入 Prisma schema 中定义的模型数据。

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'),
})

在执行变更(`create`、`update` 或 `delete`)时,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、链接、枢纽或连接表)(文档
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 提供了 `like` 和 `ilike` 的过滤器,而 Prisma ORM 提供了开发人员可以使用的更具体的运算符,例如:`contains`、`startsWith` 和 `endsWith`。

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。

附加产品

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

除了 Prisma Studio,Prisma 还通过 Prisma Data Platform 提供商业产品

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

这些产品与 Prisma ORM 携手合作,提供全面的数据工具,通过遵循 Data 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 通过 Drizzle 创建的驱动程序实现来达到这种支持,这些驱动程序与现有的第三方数据库驱动程序集成。

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

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

基准测试

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

或者,你也可以查看我们构建的基准测试工具的结果,该工具比较了包括 Drizzle 在内的流行 TypeScript ORM。该基准测试是开源的,旨在公平比较 Node.js 和 TypeScript 生态系统中数据库提供商和 ORM 库之间的数据库查询延迟。

结论

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

  • “我们从 Drizzle 转向 Prisma,因为模式漂移正在扼杀我们。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 之旅: 我们的活跃社区。保持信息灵通,参与其中,并与其他开发人员协作。

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

© . This site is unofficial and not affiliated with Prisma Data, Inc.