为什么选择 Prisma ORM?
在此页面上,你将了解 Prisma ORM 的动机以及它与传统 ORM 和 SQL 查询构建器等其他数据库工具的比较。
¥On this page, you'll learn about the motivation for Prisma ORM and how it compares to other database tools like traditional ORMs and SQL query builders.
使用关系数据库是应用开发的主要瓶颈。调试 SQL 查询或复杂的 ORM 对象通常会花费数小时的开发时间。
¥Working with relational databases is a major bottleneck in application development. Debugging SQL queries or complex ORM objects often consume hours of development time.
Prisma ORM 通过提供干净且类型安全的 API 来提交返回普通旧 JavaScript 对象的数据库查询,使开发者可以轻松推断他们的数据库查询。
¥Prisma ORM makes it easy for developers to reason about their database queries by providing a clean and type-safe API for submitting database queries which returns plain old JavaScript objects.
TLDR
Prisma ORM 的主要目标是提高应用开发者在使用数据库时的工作效率。以下是 Prisma ORM 如何实现这一目标的几个示例:
¥Prisma ORM's main goal is to make application developers more productive when working with databases. Here are a few examples of how Prisma ORM achieves this:
-
以对象的方式思考,而不是映射关系数据
¥Thinking in objects instead of mapping relational data
-
查询而不是类以避免复杂的模型对象
¥Queries not classes to avoid complex model objects
-
数据库和应用模型的单一事实来源
¥Single source of truth for database and application models
-
防止常见陷阱和反模式的健康约束
¥Healthy constraints that prevent common pitfalls and anti-patterns
-
使正确的事情变得容易的抽象 ("成功的深渊")
¥An abstraction that makes the right thing easy ("pit of success")
-
可以在编译时验证类型安全的数据库查询
¥Type-safe database queries that can be validated at compile time
-
更少的样板文件,使开发者可以专注于应用的重要部分
¥Less boilerplate so developers can focus on the important parts of their app
-
在代码编辑器中自动补齐,无需查找文档
¥Auto-completion in code editors instead of needing to look up documentation
本页的其余部分讨论 Prisma ORM 与现有数据库工具的比较。
¥The remaining parts of this page discuss how Prisma ORM compares to existing database tools.
SQL、传统 ORM 和其他数据库工具的问题
¥Problems with SQL, traditional ORMs and other database tools
Node.js 和 TypeScript 生态系统中当前存在的数据库工具的主要问题是它们需要在生产力和控制之间进行重大权衡。
¥The main problem with the database tools that currently exist in the Node.js and TypeScript ecosystem is that they require a major tradeoff between productivity and control.
原始 SQL:完全控制,生产率低
¥Raw SQL: Full control, low productivity
使用原始 SQL(例如使用原生 pg
或 mysql
Node.js 数据库驱动程序),你可以完全控制数据库操作。然而,生产力会受到影响,因为将纯 SQL 字符串发送到数据库非常麻烦,并且会带来大量开销(手动连接处理、重复的样板文件……)。
¥With raw SQL (e.g. using the native pg
or mysql
Node.js database drivers) you have full control over your database operations. However, productivity suffers as sending plain SQL strings to the database is cumbersome and comes with a lot of overhead (manual connection handling, repetitive boilerplate, ...).
这种方法的另一个主要问题是查询结果没有任何类型安全性。当然,你可以手动输入结果,但这是一项巨大的工作,并且每次更改数据库架构或查询时都需要进行重大重构以保持输入同步。
¥Another major issue with this approach is that you don't get any type safety for your query results. Of course, you can type the results manually but this is a huge amount of work and requires major refactorings each time you change your database schema or queries to keep the typings in sync.
此外,以纯字符串形式提交 SQL 查询意味着你在编辑器中不会获得任何自动补齐功能。
¥Furthermore, submitting SQL queries as plain strings means you don't get any autocompletion in your editors.
SQL 查询构建器:高控制,中等生产率
¥SQL query builders: High control, medium productivity
保留高水平控制并提供更高生产力的常见解决方案是使用 SQL 查询构建器(例如 knex.js)。此类工具提供了构建 SQL 查询的编程抽象。
¥A common solution that retains a high level of control and provides better productivity is to use a SQL query builder (e.g. knex.js). These sort of tools provide a programmatic abstraction to construct SQL queries.
SQL 查询构建器的最大缺点是应用开发者仍然需要根据 SQL 来考虑他们的数据。这会产生将关系数据转换为对象的认知和实际成本。另一个问题是,如果你不确切知道自己在 SQL 查询中做什么,很容易搬起石头砸自己的脚。
¥The biggest drawback with SQL query builders is that application developers still need to think about their data in terms of SQL. This incurs a cognitive and practical cost of translating relational data into objects. Another issue is that it's too easy to shoot yourself in the foot if you don't know exactly what you're doing in your SQL queries.
传统的 ORM:更少的控制,更高的生产力
¥Traditional ORMs: Less control, better productivity
传统的 ORM 通过让你将应用模型定义为类来抽象化 SQL,这些类映射到数据库中的表。
¥Traditional ORMs abstract away from SQL by letting you define your application models as classes, these classes are mapped to tables in the database.
"对象关系映射器"(ORM)的存在是为了弥合程序员的朋友(对象)和数据库原语(关系)之间的差距。这些不同模型的原因既有文化上的,也有功能上的:程序员喜欢对象,因为它们将单个事物的状态封装在正在运行的程序中。数据库喜欢关系,因为它们更适合整个数据集的约束和整个数据集的高效访问模式。
¥"Object relational mappers" (ORMs) exist to bridge the gap between the programmers' friend (the object), and the database's primitive (the relation). The reasons for these differing models are as much cultural as functional: programmers like objects because they encapsulate the state of a single thing in a running program. Databases like relations because they better suit whole-dataset constraints and efficient access patterns for the entire dataset.
然后,你可以通过调用模型类实例上的方法来读取和写入数据。
¥You can then read and write data by calling methods on the instances of your model classes.
这更加方便,并且更接近开发者在考虑数据时的心智模型。那么,有什么问题呢?
¥This is way more convenient and comes closer to the mental model developers have when thinking about their data. So, what's the catch?
ORM 代表着一个泥潭,开始时很好,随着时间的推移变得越来越复杂,不久就会让用户陷入一个没有明确分界点、没有明确获胜条件、也没有明确退出策略的保证。
¥ORM represents a quagmire which starts well, gets more complicated as time passes, and before long entraps its users in a commitment that has no clear demarcation point, no clear win conditions, and no clear exit strategy.
作为应用开发者,你对数据的心智模型是对象的心智模型。另一方面,SQL 中数据的心智模型是表。
¥As an application developer, the mental model you have for your data is that of an object. The mental model for data in SQL on the other hand are tables.
这两种不同的数据表示形式之间的划分通常称为 对象关系阻抗不匹配。对象关系阻抗不匹配也是许多开发者不喜欢使用传统 ORM 的主要原因。
¥The divide between these two different representations of data is often referred to as the object-relational impedance mismatch. The object-relational impedance mismatch also is a major reason why many developers don't like working with traditional ORMs.
例如,考虑如何使用每种方法组织数据和处理关系:
¥As an example, consider how data is organized and relationships are handled with each approach:
-
关系数据库:数据通常是标准化的(扁平化的),并使用外键来跨实体链接。然后需要将实体连接起来以体现实际的关系。
¥Relational databases: Data is typically normalized (flat) and uses foreign keys to link across entities. The entities then need to be JOINed to manifest the actual relationships.
-
面向对象:对象可以是深度嵌套的结构,你只需使用点表示法即可遍历关系。
¥Object-oriented: Objects can be deeply nested structures where you can traverse relationships simply by using dot notation.
这暗示了传统 ORM 的主要缺陷之一:虽然它们看起来你可以使用熟悉的点表示法简单地遍历关系,但实际上 ORM 会生成 SQL JOIN,这些 SQL JOIN 成本高昂,并且有可能大大减慢你的应用速度(其中一个症状是 n+1 问题)。
¥This alludes to one of the major pitfalls with traditional ORMs: While they make it seem that you can simply traverse relationships using familiar dot notation, under the hood the ORM generates SQL JOINs which are expensive and have the potential to drastically slow down your application (one symptom of this is the n+1 problem).
总结一下:传统 ORM 的吸引力在于抽象关系模型并纯粹从对象角度思考数据的前提。虽然前提很好,但它基于错误的假设,即关系数据可以轻松映射到对象,这会导致许多复杂性和陷阱。
¥To conclude: The appeal of traditional ORMs is the premise of abstracting away the relational model and thinking about your data purely in terms of objects. While the premise is great, it's based on the wrong assumption that relational data can easily be mapped to objects which leads to lots of complications and pitfalls.
应用开发者应该关心数据,而不是 SQL
¥Application developers should care about data – not SQL
尽管 SQL 是在 20 世纪 70 年代开发的(!),但它以令人印象深刻的方式经受住了时间的考验。然而,随着开发者工具的进步和现代化,值得一问的是,SQL 是否真的是应用开发者使用的最佳抽象?
¥Despite being developed in the 1970s(!), SQL has stood the test of time in an impressive manner. However, with the advancement and modernization of developers tools, it's worth asking if SQL really is the best abstraction for application developers to work with?
毕竟,开发者应该只关心实现某个功能所需的数据,而不是花时间计算复杂的 SQL 查询或修改查询结果来满足他们的需求。
¥After all, developers should only care about the data they need to implement a feature and not spend time figuring out complicated SQL queries or massaging query results to fit their needs.
在应用开发中还有另一个反对 SQL 的参数。如果你确切地知道自己在做什么,那么 SQL 的强大功能可能是一种祝福,但它的复杂性也可能是一种诅咒。即使是经验丰富的 SQL 用户也很难预见到许多 anti-patterns 和陷阱,通常会以性能和数小时的调试时间为代价。
¥There's another argument to be made against SQL in application development. The power of SQL can be a blessing if you know exactly what you're doing, but its complexity can be a curse. There are a lot of anti-patterns and pitfalls that even experienced SQL users struggle to anticipate, often at the cost of performance and hours of debugging time.
开发者应该能够请求他们需要的数据,而不必担心 SQL 查询中的 "做正确的事"。他们应该使用能够为他们做出正确决策的抽象。这可能意味着抽象施加了某些 "healthy" 约束,以防止开发者犯错误。
¥Developers should be able to ask for the data they need instead of having to worry about "doing the right thing" in their SQL queries. They should be using an abstraction that makes the right decisions for them. This can mean that the abstraction imposes certain "healthy" constraints that prevent developers from making mistakes.
Prisma ORM 提高开发者的工作效率
¥Prisma ORM makes developers productive
Prisma ORM 的主要目标是提高应用开发者在使用数据库时的工作效率。再次考虑生产力和控制之间的权衡,这就是 Prisma ORM 的适应方式:
¥Prisma ORM's main goal is to make application developers more productive when working with databases. Considering the tradeoff between productivity and control again, this is how Prisma ORM fits in: