Turso
本指南讨论了使用 Prisma ORM 和 Turso 背后的概念,解释了 Turso 与其他数据库提供商之间的异同,并引导你完成配置应用程序以与 Turso 集成的过程。
Prisma ORM 对 Turso 的支持目前处于早期访问 (Early Access)阶段。我们非常感谢你在本次 GitHub 讨论中提供反馈。
什么是 Turso?
Turso 是一个基于 libSQL(一个开源、开放贡献的 SQLite 分支)的边缘托管分布式数据库,它能够将数据更靠近你的应用程序,最大限度地减少查询延迟。Turso 也可以托管在远程服务器上。
从 Prisma ORM 5.4.2 版本及更高版本开始,对 Turso 的支持已处于早期访问 (Early Access)阶段。
与其他数据库提供商的共同点
libSQL 与 SQLite 100% 兼容。libSQL 扩展了 SQLite 并添加了以下特性和功能
- 支持复制
- 支持自动备份
- 能够将 Turso 作为其他程序(例如 Linux 内核)的一部分进行嵌入
- 支持用户定义函数
- 支持异步 I/O
要了解有关 libSQL 与 SQLite 的更多区别,请参阅 libSQL 宣言。
将 Prisma ORM 与 Turso 一起使用的许多方面都与将 Prisma ORM 与任何其他关系型数据库一起使用类似。你仍然可以
- 使用 Prisma Schema 语言建模你的数据库
- 在你的 schema 中使用 Prisma ORM 现有的
sqlite
数据库连接器 - 在你的应用程序中使用 Prisma Client 与 Turso 上的数据库服务器通信
需要考虑的区别
Turso 和 SQLite 之间存在一些需要考虑的区别。在决定使用 Turso 和 Prisma ORM 时,你应该了解以下内容
- 远程和嵌入式 SQLite 数据库。libSQL 使用 HTTP 连接到远程 SQLite 数据库。libSQL 还支持远程数据库副本和嵌入式副本。嵌入式副本使你能够在应用程序内部复制主数据库。
- 进行 schema 更改。由于 libSQL 使用 HTTP 连接到远程数据库,这使得它与 Prisma Migrate 不兼容。但是,你可以使用
prisma migrate diff
创建一个 schema 迁移,然后使用 Turso 的 CLI 将更改应用到数据库。
如何连接和查询 Turso 数据库
下一节介绍如何创建 Turso 数据库、检索数据库凭据以及连接到数据库。
如何创建数据库并检索数据库凭据
请确保已安装 Turso CLI 来管理你的数据库。
如果你没有现有的数据库,可以运行以下命令来创建数据库
turso db create turso-prisma-db
上述命令将在离你位置最近的区域创建一个数据库。
运行以下命令以检索你的数据库连接字符串
turso db show turso-prisma-db
接下来,创建一个认证令牌,它将允许你连接到数据库
turso db tokens create turso-prisma-db
使用认证令牌和连接字符串更新你的 .env
文件
TURSO_AUTH_TOKEN="eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
TURSO_DATABASE_URL="libsql://turso-prisma-db-user.turso.io"
如何连接到 Turso 数据库
开始之前,启用 driverAdapters
预览特性标志
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "sqlite"
url = "file:./dev.db" // will be ignored
}
生成 Prisma Client
npx prisma generate
安装 Prisma ORM 的 libSQL 驱动适配器包
npm install @prisma/adapter-libsql
更新你的 Prisma Client 实例
import { PrismaClient } from '@prisma/client'
import { PrismaLibSQL } from '@prisma/adapter-libsql'
const adapter = new PrismaLibSQL({
url: `${process.env.TURSO_DATABASE_URL}`,
authToken: `${process.env.TURSO_AUTH_TOKEN}`,
})
const prisma = new PrismaClient({ adapter })
你可以在你的项目中像往常一样使用 Prisma Client,并享受完全的类型安全。
在 prisma.config.ts
中通过驱动适配器使用 Prisma Migrate (早期访问)
从 v6.6.0 版本开始,并配合 prisma.config.ts
文件,你可以使用 prisma db push
来修改你的数据库 schema。
此功能已在 v6.6.0 中作为早期访问 (Early Access)特性引入,支持以下命令
prisma db push
prisma db pull
prisma migrate diff
其他命令,如 prisma migrate dev
和 prisma migrate deploy
,将很快添加。
1. 安装 LibSQL 驱动适配器
在你的终端中运行此命令
npm install @prisma/adapter-libsql
2. 设置环境变量
为了设置 LibSQL 适配器,你需要将一些秘密添加到 .env
文件中
LIBSQL_DATABASE_URL
: 你的 Turso 数据库实例的连接 URL。LIBSQL_DATABASE_TOKEN
: 你的 Turso 数据库实例的令牌。
然后你可以将这些添加到你的 .env
文件中,或者如果它们存储在不同的秘密存储中,则直接使用它们
LIBSQL_DATABASE_URL="..."
LIBSQL_DATABASE_TOKEN="..."
3. 设置 Prisma Config 文件
确保你的项目有一个 prisma.config.ts
文件。然后,设置 migration 驱动适配器以使用 PrismaLibSQL
import path from 'node:path'
import { defineConfig } from 'prisma/config'
import { PrismaLibSQL } from '@prisma/adapter-libsql'
// import your .env file
import 'dotenv/config'
type Env = {
LIBSQL_DATABASE_URL: string
LIBSQL_DATABASE_TOKEN: string
}
export default defineConfig<Env>({
earlyAccess: true,
schema: path.join('prisma', 'schema.prisma'),
migrate: {
async adapter(env) {
return new PrismaLibSQL({
url: env.LIBSQL_DATABASE_URL,
authToken: env.LIBSQL_DATABASE_TOKEN,
})
}
}
})
4. 迁移你的数据库
现在 Prisma Migrate 将根据 prisma.config.ts
中提供的配置,对你的远程 Turso 数据库运行迁移。
要使用此工作流程创建你的第一次迁移,请运行以下命令
npx prisma db push
嵌入式 Turso 数据库副本
Turso 支持嵌入式副本。Turso 的嵌入式副本使你能够在应用程序内部拥有主远程数据库的副本。嵌入式副本的行为类似于本地 SQLite 数据库。数据库查询速度更快,因为你的数据库就在应用程序内部。
嵌入式数据库副本如何工作
当你的应用程序最初与数据库建立连接时,主数据库将处理查询
Turso 将 (1) 在你的应用程序内部创建一个嵌入式副本,并 (2) 将主数据库中的数据复制到该副本,以便本地可用
嵌入式副本将处理后续的读取查询。libSQL 客户端提供了一个 sync()
方法,你可以调用它来确保嵌入式副本的数据保持最新。
使用嵌入式副本,这种设置保证了应用程序的响应速度,因为数据将在本地随时可用且访问速度更快。
类似于你可能熟悉的读取副本设置,写入操作会转发到主远程数据库并执行,然后再传播到所有嵌入式副本。
- 写入操作的传播会转发到数据库。
- 数据库将来自 1 的更新响应给服务器。
- 写入操作传播到数据库副本。
你的应用程序的数据需求将决定你应多久同步一次远程数据库和嵌入式数据库副本之间的数据。例如,你可以使用中间件函数(例如 Express 和 Fastify)或 cron 作业来同步数据。
如何同步远程数据库和嵌入式副本之间的数据
要开始将嵌入式副本与 Prisma ORM 一起使用,请在应用程序中添加来自 libSQL 的 sync()
方法。下面的示例展示了如何使用 Express 中间件同步数据。
import express from 'express'
const app = express()
// ... the rest of your application code
app.use(async (req, res, next) => {
await libsql.sync()
next()
})
app.listen(3000, () => console.log(`Server ready at http://localhost:3000`))
它也可以实现为 Prisma Client 扩展。下面的示例展示了在执行创建、更新或删除操作后自动同步。
const prisma = new PrismaClient().$extends({
query: {
$allModels: {
async $allOperations({ operation, model, args, query }) {
const result = await query(args)
// Synchronize the embedded replica after any write operation
if (['create', 'update', 'delete'].includes(operation)) {
await libsql.sync()
}
return result
}
}
}
})