Drizzle
Prisma 和 Drizzle 在使用数据库方面采取了不同的方法。Drizzle 对喜欢编写接近 SQL 的查询的开发者很有吸引力,而 Prisma 则旨在支持构建和维护生产应用程序的团队——清晰性、协作性和长期可维护性至关重要。
虽然这两个库解决了类似的问题,但它们的工作方式非常不同,各有优缺点。选择哪个将取决于您的项目需求以及对其重要的具体权衡。
Drizzle vs Prisma ORM
Drizzle 是一个传统的 SQL 查询构建器,它允许您使用 JavaScript/TypeScript 函数组合 SQL 查询。它可用于查询数据库或运行迁移。Drizzle 还提供了一个 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 自动化了迁移生成、客户端类型化和查询构建——因此您的团队无需手动完成这些工作。
对于精通 SQL 或喜欢学习 SQL 的单个开发者来说,Drizzle 可能很棒。但一旦您组建了团队,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 生成了一个轻量级数据库客户端,它为 Prisma schema 中定义的模型公开了一个定制的、完全类型安全的 API,用于读写数据,遵循 DataMapper ORM 模式。
Prisma ORM 的数据建模 DSL 精简、简单且直观易用。在 VS Code 中建模数据时,您可以进一步利用 Prisma ORM 强大的VS Code 扩展,它提供了自动补全、快速修复、跳转到定义等功能,从而提高开发者生产力。另一方面,Drizzle 使用 TypeScript 意味着您可以利用 TypeScript 的强大功能获得额外的灵活性(例如通过代码重用)。
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])
}
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,这两种方法非常相似
// 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' },
})
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'),
})
执行 mutation 操作(create
、update
或 delete
)时,Drizzle Queries API 不可用。在这些情况下,您需要使用 Drizzle 的类似 SQL 的 API
// 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' },
})
// 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、链接表、枢纽表或连接表)(文档)
const posts = await prisma.post.findMany({
include: {
author: true,
},
})
const posts = await db.query.posts.findMany({
with: {
author: true,
},
})
过滤
Drizzle 暴露了给定 SQL 方言的底层过滤器和条件运算符。另一方面,Prisma ORM 提供了一组更通用的运算符,这些运算符直观易用。
一个很好的例子来说明 Drizzle 和 Prisma ORM 的过滤 API 如何不同,就是看看字符串
过滤器。Drizzle 提供like
和ilike
过滤器,而 Prisma ORM 提供更具体的开发者可使用的运算符,例如:contains
、startsWith
和 endsWith
。
// 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',
},
})
// 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'))
const posts = await prisma.post.findMany({
where: {
title: {
contains: 'Hello World',
},
},
})
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, '%Hello World%'))
const posts = await prisma.post.findMany({
where: {
title: {
startsWith: 'Hello World',
},
},
})
const posts = await db
.select()
.from(posts)
.where(ilike(posts.title, 'Hello World%'))
const posts = await prisma.post.findMany({
where: {
title: {
endsWith: 'Hello World',
},
},
})
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 协同工作,提供全面的数据工具,遵循Data DX原则,使构建数据驱动型应用程序变得容易。
更安全的变化和更少的 Bug
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 也被许多元框架和开发平台选为首选的数据层工具,例如 Amplication、Wasp、RedwoodJS、KeystoneJS、Remix 和 t3 stack。
由于其成熟度,Prisma 社区开发了大量有用的工具,可帮助处理各种 Prisma 工作流程。以下是一些亮点:
prisma-erd-generator
: 将 Prisma schema 可视化为实体关系图 (ERD)。prisma-zod-generator
: 从 Prisma schema 生成 Zod schemas。bridg
: 允许您使用 Prisma Client 从前端访问数据库。jest-prisma
: 用于与 Jest 集成测试的 Prisma 环境。prisma-pothos-types
: 使用 GraphQL Pothos 时,根据 Prisma 模型创建 GraphQL 类型。prisma-trpc-generator
: 从 Prisma schema 创建 tRPC 路由。@cerbos/orm-prisma
: 根据来自 Cerbos 的授权策略过滤数据。
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 Proxy 的 SQLite,而 Prisma ORM 目前不支持这些。
基准测试
我们理解性能是选择 ORM 时的一个关键考虑因素。要比较各种 ORM 的性能,您可以使用 Vercel 托管的开源数据库延迟基准测试工具。此工具允许您评估各种 ORM 在不同工作负载和配置下的延迟和吞吐量。通过对您正在考虑的数据库或数据库提供商运行基准测试,您可以清楚地了解它们的相对性能特征,从而做出明智的决定。
另外,您还可以查看我们构建的基准测试工具上的结果,该工具比较了包括 Drizzle 在内的流行 TypeScript ORM。这个基准测试是开源的,旨在公平比较 Node.js 和 TypeScript 生态系统中不同数据库提供商和 ORM 库之间的数据库查询延迟。
结论
是的,我们带有偏见,但这也是我们从用户和客户那里听到的反馈
- "我们从 Drizzle 转向 Prisma,因为 schema drift 让我们头疼不已。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 之旅 与我们活跃的社区联系。了解最新信息,参与其中,并与其他开发者协作
- 在 X 上关注我们 获取公告、直播活动和实用技巧。
- 加入我们的 Discord 提问、与社区交流,并通过对话获得积极支持。
- 在 YouTube 上订阅 获取教程、演示和直播。
- 在 GitHub 上参与 通过点赞仓库、报告问题或贡献代码参与其中。