PlanetScale
Prisma 與 PlanetScale 共同提供了一個開發平臺,利用 Prisma 的 ORM 和 PlanetScale 的高度可伸縮的基於 MySQL 的平臺,優化了資料訪問應用的快速、型別安全開發。
本文件討論了使用 Prisma ORM 和 PlanetScale 的概念,解釋了 PlanetScale 與其他資料庫提供商之間的異同,並引導你完成配置應用程式以與 PlanetScale 整合的過程。
什麼是 PlanetScale?
PlanetScale 使用 Vitess 資料庫集群系統來提供一個相容 MySQL 的資料庫平臺。功能包括
- 企業級可伸縮性。PlanetScale 提供了一個高可用的生產資料庫叢集,支援跨多個數據庫伺服器進行擴充套件。這在無伺服器環境中特別有用,因為它避免了 管理連線限制 的問題。
- 資料庫分支。PlanetScale 允許你建立 資料庫 schema 分支,這樣你就可以在將更改應用於生產資料庫之前,在開發分支上測試這些更改。
- 支援 無阻塞 schema 更改。PlanetScale 提供了一種工作流,允許使用者更新資料庫 schema,而無需鎖定資料庫或導致停機。
與其他資料庫提供商的共同點
使用 Prisma ORM 與 PlanetScale 的許多方面都與使用 Prisma ORM 與任何其他關係型資料庫一樣。你仍然可以
- 使用 Prisma Schema 語言 對你的資料庫進行建模
- 在你的 schema 中使用 Prisma ORM 現有的
mysql資料庫聯結器,以及 PlanetScale 提供給你的連線字串 - 如果你在 PlanetScale 中已經有資料庫 schema,可以使用 內省 功能用於現有專案
- 使用
db push將你的 schema 更改推送到資料庫 - 在你的應用程式中使用 Prisma Client 與 PlanetScale 的資料庫伺服器通訊
需要考慮的差異
PlanetScale 的分支模型和可伸縮性設計意味著還需要考慮一些差異。在決定將 PlanetScale 與 Prisma ORM 結合使用時,你應該注意以下幾點
-
分支和部署請求。PlanetScale 提供兩種型別的資料庫分支:開發分支,允許你測試 schema 更改;以及生產分支,受到直接 schema 更改的保護。相反,更改必須首先在開發分支上建立,然後使用部署請求部署到生產環境。生產分支具有高可用性,幷包括每日自動備份。要了解更多資訊,請參閱 如何使用分支和部署請求。
-
引用操作和完整性。為了支援跨多個數據庫伺服器的擴充套件,PlanetScale 預設不使用外部索引鍵約束,這些約束通常用於關係型資料庫中以強制執行不同表之間的資料關係,並要求使用者在他們的應用程式中手動處理。但是,你可以透過 在 PlanetScale 資料庫設定中顯式啟用它們。如果你沒有顯式啟用它們,你仍然可以在資料中維護這些關係,並允許使用 引用操作,方法是利用 Prisma ORM 的能力,在
prisma關係模式下 在 Prisma Client 中模擬關係。有關更多資訊,請參閱 如何在 Prisma Client 中模擬關係。 -
在外部索引鍵上建立索引。當 在 Prisma ORM 中模擬關係 時(即不在資料庫層面使用外部索引鍵約束時),你需要在外部索引鍵上建立專用索引。在標準 MySQL 資料庫中,如果一個表有一列帶有外部索引鍵約束,那麼該列上會自動建立一個索引。當 PlanetScale 配置為不使用外部索引鍵約束時,在 Prisma Client 模擬關係時,這些索引 目前 不會被建立,這可能導致查詢最佳化不佳。為避免此問題,你可以在 Prisma ORM 中建立索引。有關更多資訊,請參閱 如何建立外部索引鍵索引。
-
使用
db push進行 schema 更改。當你將開發分支合併到生產分支時,PlanetScale 將自動比較這兩個 schema 並生成其自己的 schema 差異。這意味著 Prisma ORM 的prisma migrate工作流(它會生成自己的遷移檔案歷史記錄)在使用 PlanetScale 時並不自然契合。這些遷移檔案可能無法反映分支合併時 PlanetScale 實際執行的 schema 更改。警告我們建議在與 PlanetScale 進行 schema 更改時不要使用
prisma migrate。相反,我們建議你使用prisma db push命令。有關其工作原理的示例,請參閱 如何使用
db push進行 schema 更改 -
內省。當你對現有資料庫進行內省,並且沒有在 你的 PlanetScale 資料庫中啟用外部索引鍵約束 時,你將得到一個沒有關係的 schema,因為關係通常是基於連線表的外部索引鍵定義的。在這種情況下,你需要手動新增缺失的關係。有關更多資訊,請參閱 內省後如何新增缺失的關係。
如何使用分支和部署請求
使用 Prisma ORM 連線到 PlanetScale 時,你需要為你的分支使用正確的連線字串。給定資料庫分支的連線 URL 可以在你的 PlanetScale 賬戶中找到,方法是進入分支的概覽頁面並選擇“連線”下拉選單。在“密碼”部分,生成一個新密碼並從下拉選單中選擇“Prisma”以獲取 Prisma 格式的連線 URL。有關如何連線到 PlanetScale 資料庫的更多詳細資訊,請參閱 Prisma ORM 的 入門指南。
每個 PlanetScale 資料庫都會建立一個名為 main 的分支,它最初是一個開發分支,你可以用它來測試 schema 更改。一旦你對所做的更改滿意,就可以 將其提升 為生產分支。請注意,你只能將新更改推送到開發分支,因此後續更改需要在單獨的開發分支上建立,然後透過 部署請求 部署到生產環境。
如果你嘗試推送到生產分支,你將收到 錯誤訊息 Direct execution of DDL (Data Definition Language) SQL statements is disabled on this database.。
如何在 PlanetScale 中使用關係(並啟用引用完整性)
選項 1:在 Prisma Client 中模擬關係
1. 設定 relationMode = "prisma"
PlanetScale 預設不在其資料庫 schema 中使用外部索引鍵約束。然而,Prisma ORM 依賴於底層資料庫中的外部索引鍵約束來強制執行你的 Prisma schema 中模型之間的引用完整性。
在 Prisma ORM 3.1.1 及更高版本中,你可以 在 Prisma Client 中使用 prisma 關係模式模擬關係,這避免了資料庫中需要外部索引鍵約束。
要在 Prisma Client 中啟用關係模擬,請在 datasource 塊中將 relationMode 欄位設定為 "prisma"
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
設定關係模式的功能作為 referentialIntegrity 預覽功能的一部分在 Prisma ORM 3.1.1 版本中引入,並在 Prisma ORM 4.8.0 及更高版本中普遍可用。relationMode 欄位在 Prisma ORM 4.5.0 版本中被重新命名,之前名為 referentialIntegrity。
如果你的 Prisma schema 中的關係使用 relationMode 欄位的預設選項 "foreignKeys",當 PlanetScale 嘗試建立外部索引鍵時,將會出錯,Prisma ORM 會輸出 P3021 錯誤訊息。(在 2.27.0 之前的版本中,它會輸出原始資料庫錯誤。)
2. 在外部索引鍵上建立索引
當 你在 Prisma Client 中模擬關係 時,你需要建立自己的索引。舉一個需要新增索引的例子,考慮以下一個包含文章和評論的部落格 schema
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 欄位上定義一個索引
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 將此更改新增到你的 schema 中。
在 4.7.0 及更高版本中,如果你的關係標量欄位上沒有索引,Prisma ORM 會發出警告。有關更多資訊,請參閱 索引驗證。
選項 2:在 PlanetScale 資料庫設定中啟用外部索引鍵約束
PlanetScale 資料庫對外部索引鍵約束的支援已於 2024 年 2 月全面可用。請按照 PlanetScale 文件 中的說明在你的資料庫中啟用它們。
然後,你就可以使用 Prisma ORM 並在你的 Prisma schema 中定義關係,而無需額外的配置。
在這種情況下,你可以像使用其他支援外部索引鍵約束的資料庫一樣定義關係,例如
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 schema 中設定
relationMode = "prisma" - 在外部索引鍵上定義額外索引
此外,內省會自動在你的 Prisma schema 中建立關係欄位,因為它可以檢測到資料庫中的外部索引鍵約束。
如何使用 db push 進行 schema 更改
要將 db push 與 PlanetScale 一起使用,你首先需要 在 Prisma Client 中啟用關係模擬。在未啟用引用模擬的情況下推送到你的分支,將導致 錯誤訊息 Foreign keys cannot be created on this database.。
例如,假設你決定在上述部落格文章 schema 中新增一個新的 excerpt 欄位。你首先需要 建立一個新的開發分支並連線到它。
接下來,將以下內容新增到你的 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 進行內省後,你得到的 schema 可能會缺少一些關係。例如,以下 schema 缺少 User 和 Post 模型之間的關係
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?
}
在這種情況下,你需要手動新增關係
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 schema 中定義分片鍵(預覽)
分片 是一種在資料庫負載增長時進行擴充套件的流行技術。
截至 v6.10.0,Prisma ORM 原生支援 PlanetScale 上的分片(作為一項 預覽 功能),透過 Prisma schema 中的 @shardKey 和 @@shardKey 屬性,你可以將其應用於模型中應作為資料庫設定中分片鍵的欄位。
為了使用分片鍵屬性,你需要在 generator 上指定 shardKeys 預覽功能
generator client {
provider = "prisma-client-js"
output = "../generated/prisma"
previewFeatures = ["shardKeys"]
}
現在你可以使用 @shardKey 和 @@shardKey 屬性了
單列分片鍵
model User {
id String @default(uuid())
region String @shardKey
}
多列分片鍵
model User {
id String @default(uuid())
country String
customerId String
@@shardKey([country, customerId])
}
如何在 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:strongpassword@aws.connect.psdb.cloud/clear_nightsky?sslaccept=strict'
安裝用於 PlanetScale 的 Prisma ORM 介面卡、PlanetScale 無伺服器驅動和 undici 包
npm install @prisma/adapter-planetscale undici
當使用 Node.js 18 以下的版本時,你必須提供一個自定義的 fetch 函式實現。我們推薦使用 undici 包,Node.js 內建的 fetch 函式就是基於它。Node.js 18 及更高版本包含一個內建的全域性 fetch 函式,所以你無需安裝額外的包。
更新你的 Prisma Client 例項以使用 PlanetScale 無伺服器驅動
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 adapter = new PrismaPlanetScale({ url: connectionString, fetch: undiciFetch })
const prisma = new PrismaClient({ adapter })
然後,你可以像往常一樣使用 Prisma Client,並享受完全的型別安全。Prisma Migrate、內省和 Prisma Studio 將繼續使用 Prisma schema 中定義的連線字串照常工作。
更多關於將 PlanetScale 與 Prisma ORM 結合使用的資訊
開始將 PlanetScale 與 Prisma ORM 結合使用的最快方法是查閱我們的入門文件
這些教程將引導你完成連線到 PlanetScale、推送 schema 更改以及使用 Prisma Client 的過程。
有關將 Prisma ORM 和 PlanetScale 結合使用時的最佳實踐的更多提示,請觀看我們的影片