跳到主要内容

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 帐户中找到,方法是转到该分支的概览页面并选择“连接”下拉菜单。在“密码”部分中,生成新密码并从下拉菜单中选择“Prisma”以获取连接 URL 的 Prisma 格式。有关如何连接到 PlanetScale 数据库的更多详细信息,请参阅 Prisma ORM 的 入门指南

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

如果您尝试推送到生产分支,您将收到 错误消息 Direct execution of DDL (Data Definition Language) SQL statements is disabled on this database.

如何使用关系(并启用引用完整性)与 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 中模拟关系。在未启用引用模拟的情况下推送到您的分支将给出 错误消息 Foreign keys cannot be created on this database.

例如,假设您决定向上面的博客文章模式添加一个新的 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
信息

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

DATABASE_URL='mysql://johndoe:[email protected]/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 一起使用时的最佳实践的更多提示,请观看我们的视频