跳至主要内容

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”,即可获取 Prisma 格式的连接 URL。有关如何连接到 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 数据库中的外键约束支持已普遍可用。请按照 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 关于 使用 Prisma ORM 进行自动迁移 使用 db push 的教程。

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

注意:此部分仅在您使用 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 入门指南

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

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:[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 结合使用时的最佳实践的更多提示,请观看我们的视频