跳到主要内容

PlanetScale

Prisma 和 PlanetScale 共同提供了一个开发平台,该平台优化了数据访问应用程序的快速、类型安全开发,使用了 Prisma 的 ORM 和 PlanetScale 的高度可扩展的基于 MySQL 的平台。

本文档讨论了使用 Prisma ORM 和 PlanetScale 背后的概念,解释了 PlanetScale 与其他数据库提供商之间的共性和差异,并引导您完成配置应用程序以与 PlanetScale 集成的过程。

什么是 PlanetScale?

PlanetScale 使用 Vitess 数据库集群系统来提供 MySQL 兼容的数据库平台。功能包括:

  • 企业级可扩展性。 PlanetScale 提供高度可用的生产数据库集群,支持跨多个数据库服务器进行扩展。这在无服务器环境中尤其有用,因为它避免了必须管理连接限制的问题。
  • 数据库分支。 PlanetScale 允许您创建 数据库模式的分支,以便您可以在开发分支上测试更改,然后再将其应用到生产数据库。
  • 支持 非阻塞模式更改 PlanetScale 提供了一个工作流程,允许用户在不锁定数据库或导致停机的情况下更新数据库模式。

与其他数据库提供商的共性

将 Prisma ORM 与 PlanetScale 结合使用的许多方面就像将 Prisma ORM 与任何其他关系数据库结合使用一样。您仍然可以:

需要考虑的差异

PlanetScale 的分支模型和可扩展性设计意味着还有许多差异需要考虑。当您决定将 PlanetScale 与 Prisma ORM 一起使用时,您应该注意以下几点:

  • 分支和部署请求。 PlanetScale 提供两种类型的数据库分支:开发分支,允许您测试模式更改;以及生产分支,受到保护,免受直接模式更改的影响。相反,更改必须首先在开发分支上创建,然后使用部署请求部署到生产环境。生产分支具有高可用性,并包含每日自动备份。要了解更多信息,请参阅如何使用分支和部署请求

  • 参照操作和完整性。 为了支持跨多个数据库服务器进行扩展,PlanetScale 默认情况下不使用外键约束,外键约束通常在关系数据库中用于强制执行不同表中的数据之间的关系,并要求用户在其应用程序中手动处理此问题。但是,您可以显式地 在 PlanetScale 数据库设置中启用它们。如果您不显式启用这些约束,您仍然可以在数据中维护这些关系,并通过使用 Prisma ORM 的能力 在 Prisma Client 中模拟关系 来允许使用 参照操作,使用 prisma 关系模式。有关更多信息,请参阅如何在 Prisma Client 中模拟关系

  • 在外键上创建索引。在 Prisma ORM 中模拟关系 时(即,当在数据库级别使用外键约束时),您将需要在外键上创建专用索引。在标准的 MySQL 数据库中,如果一个表有一列带有外键约束,则会自动在该列上创建索引。当 PlanetScale 配置为不使用外键约束时,当 Prisma Client 模拟关系时,这些索引目前不会被创建,这可能会导致查询未得到良好优化的问题。为了避免这种情况,您可以在 Prisma ORM 中创建索引。有关更多信息,请参阅如何在外键上创建索引

  • 使用 db push 进行模式更改。 当您将开发分支合并到生产分支时,PlanetScale 将自动比较两个模式并生成自己的模式差异。这意味着 Prisma ORM 的 prisma migrate 工作流程(生成其自身的迁移文件历史记录)在与 PlanetScale 一起使用时不太自然。这些迁移文件可能无法反映 PlanetScale 在合并分支时运行的实际模式更改。

    警告

    我们建议在使用 PlanetScale 进行模式更改时不要使用 prisma migrate。相反,我们建议您使用 prisma db push 命令。

    有关其工作原理的示例,请参阅如何使用 db push 进行模式更改

  • 内省。当您对现有数据库进行内省,并且您没有PlanetScale 数据库中启用外键约束 时,您将获得一个没有关系的模式,因为关系通常是基于连接表的外键定义的。在这种情况下,您将需要手动添加缺少的关系。有关更多信息,请参阅如何在内省后添加缺少的关联关系

如何使用分支和部署请求

当将 Prisma ORM 连接到 PlanetScale 时,您将需要为您的分支使用正确的连接字符串。给定数据库分支的连接 URL 可以从您的 PlanetScale 帐户中找到,方法是转到分支的概览页面并选择“Connect”下拉菜单。在“Passwords”部分,生成一个新密码,然后从下拉菜单中选择“Prisma”,以获取连接 URL 的 Prisma 格式。有关如何连接到 PlanetScale 数据库的更多详细信息,请参阅 Prisma ORM 的入门指南

每个 PlanetScale 数据库都创建了一个名为 main 的分支,最初是一个开发分支,您可以使用它来测试模式更改。一旦您对在那里所做的更改感到满意,您可以 将其升级 为生产分支。请注意,您只能将新更改推送到开发分支,因此进一步的更改将需要在单独的开发分支上创建,然后稍后使用 部署请求 部署到生产环境。

如果您尝试推送到生产分支,您将收到 错误消息 在此数据库上禁用了 DDL(数据定义语言)SQL 语句的直接执行。

如何将关系(和启用参照完整性)与 PlanetScale 一起使用

选项 1:在 Prisma Client 中模拟关系

1. 设置 relationMode = "prisma"

PlanetScale 默认情况下不在其数据库模式中使用外键约束。但是,Prisma ORM 依赖于底层数据库中的外键约束来强制执行 Prisma 模式中模型之间的参照完整性。

在 Prisma ORM 3.1.1 及更高版本中,您可以使用 prisma 关系模式在 Prisma Client 中模拟关系,这避免了数据库中对外键约束的需求。

要在 Prisma Client 中启用关系模拟,请在 datasource 块中将 relationMode 字段设置为 "prisma"

schema.prisma
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
信息

设置关系模式的功能作为 Prisma ORM 3.1.1 版本中 referentialIntegrity 预览功能的一部分引入,并在 Prisma ORM 4.8.0 及更高版本中普遍可用。

relationMode 字段在 Prisma ORM 4.5.0 版本中重命名,之前名为 referentialIntegrity

如果您在 Prisma 模式中使用关系,并且为 relationMode 字段使用了默认的 "foreignKeys" 选项,则 PlanetScale 将报错,并且当 Prisma ORM 尝试创建外键时,会输出 P3021 错误消息。(在 2.27.0 之前的版本中,它将输出原始数据库错误。)

2. 在外键上创建索引

在 Prisma Client 中模拟关系时,您需要创建自己的索引。举例说明您可能想要添加索引的情况,以下是一个带有帖子和评论的博客模式:

schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
content String
likes Int @default(0)
comments Comment[]
}

model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
}

Comment 模型中的 postId 字段引用了 Post 模型中对应的 id 字段。但是,这在 PlanetScale 中未作为外键实现,因此该列没有自动索引。这意味着某些查询可能未得到良好优化。例如,如果您查询具有特定帖子 id 的所有评论,PlanetScale 可能必须执行全表查找。这可能会很慢,而且也很昂贵,因为 PlanetScale 的计费模型按读取的行数收费。

为了避免这种情况,您可以使用 Prisma ORM 的 @@index 参数postId 字段上定义索引:

schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
content String
likes Int @default(0)
comments Comment[]
}

model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)

@@index([postId])
}

然后,您可以使用 db push 将此更改添加到您的模式中。

在 4.7.0 及更高版本中,如果您有一个关系在关系标量字段上没有索引,Prisma ORM 会发出警告。有关更多信息,请参阅索引验证

警告

需要注意的一个问题是,隐式多对多关系 无法以这种方式添加索引。如果查询速度或成本是一个问题,您可能希望在这种情况下使用显式多对多关系

选项 2:在 PlanetScale 数据库设置中启用外键约束

自 2024 年 2 月起,PlanetScale 数据库中对外键约束的支持已正式发布 (Generally Available)。按照 PlanetScale 文档 中的说明在您的数据库中启用它们。

然后,您可以使用 Prisma ORM 并在您的 Prisma 模式中定义关系,而无需额外的配置。

在这种情况下,您可以像使用其他支持外键约束的数据库一样定义关系,例如:

schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
content String
likes Int @default(0)
comments Comment[]
}

model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
}

使用这种方法,无需

  • 在您的 Prisma 模式中设置 relationMode = "prisma"
  • 在外键上定义额外的索引

此外,内省将自动在您的 Prisma 模式中创建关系字段,因为它可以在数据库中检测到外键约束。

如何使用 db push 进行模式更改

要将 db push 与 PlanetScale 一起使用,您首先需要启用 Prisma Client 中的关系模拟。在未启用参照模拟的情况下推送到您的分支将给出错误消息 无法在此数据库上创建外键。

例如,假设您决定在上面的博客文章模式中添加一个新的 excerpt 字段。您首先需要创建一个新的开发分支并连接到它

接下来,将以下内容添加到您的 schema.prisma 文件中:

schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
content String
excerpt String?
likes Int @default(0)
comments Comment[]
}

model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)

@@index([postId])
}

要推送这些更改,请在您的终端中导航到您的项目目录并运行:

npx prisma db push

一旦您对开发分支上的更改感到满意,您可以打开一个部署请求以将这些更改部署到您的生产分支。

有关更多示例,请参阅 PlanetScale 关于使用 db push 进行 Prisma ORM 自动迁移 的教程。

如何在内省后添加缺少的关联关系

注意:本节仅在您使用 relationMode = "prisma" 来模拟 Prisma ORM 的外键约束时相关。如果您在 PlanetScale 数据库中启用了外键约束,则可以忽略本节。

在使用 npx prisma db pull 进行内省后,您获得的模式可能会缺少一些关系。例如,以下模式缺少 UserPost 模型之间的关系:

schema.prisma
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String @db.VarChar(255)
content String?
authorId Int

@@index([authorId])
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}

在这种情况下,您需要手动添加关系:

schema.prisma
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String @db.VarChar(255)
content String?
author User @relation(fields: [authorId], references: [id])
authorId Int

@@index([authorId])
}

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

有关更详细的示例,请参阅 PlanetScale 入门指南

如何将 PlanetScale 无服务器驱动程序与 Prisma ORM 一起使用(预览版)

PlanetScale 无服务器驱动程序 提供了一种通过 HTTP 与数据库通信并执行查询的方法。

您可以将 Prisma ORM 与 PlanetScale 无服务器驱动程序一起使用,方法是使用 @prisma/adapter-planetscale 驱动程序适配器。驱动程序适配器允许您通过 HTTP 与数据库通信。

信息

此功能在 Prisma ORM 5.4.2 及更高版本中以预览版提供。

要开始使用,请启用 driverAdapters 预览功能标志:

generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}

生成 Prisma Client:

npx prisma generate
信息

确保您将连接字符串中的主机值更新为 aws.connect.psdb.cloud。您可以在此处了解更多信息。

DATABASE_URL='mysql://johndoe:strongpassword@aws.connect.psdb.cloud/clear_nightsky?sslaccept=strict'

安装适用于 PlanetScale 的 Prisma ORM 适配器、PlanetScale 无服务器驱动程序和 undici 软件包:

npm install @prisma/adapter-planetscale @planetscale/database undici
信息

当使用低于 18 的 Node.js 版本时,您必须提供自定义的 fetch 函数实现。我们推荐使用 undici 软件包,Node 的内置 fetch 基于该软件包。Node.js 18 及更高版本包含内置的全局 fetch 函数,因此您无需安装额外的软件包。

更新您的 Prisma Client 实例以使用 PlanetScale 无服务器驱动程序:

import { Client } from '@planetscale/database'
import { PrismaPlanetScale } from '@prisma/adapter-planetscale'
import { PrismaClient } from '@prisma/client'
import dotenv from 'dotenv'
import { fetch as undiciFetch } from 'undici'

dotenv.config()
const connectionString = `${process.env.DATABASE_URL}`

const client = new Client({ url: connectionString, fetch: undiciFetch })
const adapter = new PrismaPlanetScale(client)
const prisma = new PrismaClient({ adapter })

然后,您可以像往常一样使用 Prisma Client,并具有完整的类型安全性。Prisma Migrate、内省和 Prisma Studio 将继续像以前一样使用 Prisma 模式中定义的连接字符串工作。

有关将 PlanetScale 与 Prisma ORM 一起使用的更多信息

开始将 PlanetScale 与 Prisma ORM 一起使用的最快方法是参考我们的入门文档:

这些教程将引导您完成连接到 PlanetScale、推送模式更改以及使用 Prisma Client 的过程。

有关将 Prisma ORM 和 PlanetScale 一起使用时的最佳实践的更多提示,请观看我们的视频: