☰
SvelteKit 集成 Prisma Accelerate 实战:在名言生成器中落地 TTL、SWR 与 TTL+SWR 缓存策略
2026/10/15 15:36:10 网站建设 项目流程
  • 示例工程

【免费下载链接】prisma-examples

🚀 Ready-to-run Prisma example projects

项目地址:https://gitcode.com/gh_mirrors/pr/prisma-examples
点击查看免费下载

本文基于 prisma-examples 仓库中的 accelerate/svelte-starter 项目,讲解如何在 SvelteKit 应用中接入 Prisma ORM 与 Prisma Accelerate,用最小的代码闭环演示四种缓存策略(TTL、SWR、TTL+SWR 与不缓存)的配置、请求处理与命中观测。读完你将掌握 Accelerate 连接串的配置方式、cacheStrategy参数的取值与语义、基于withAccelerateInfo()的缓存元数据解读,以及一条从建表、灌数据到启动页面的完整可运行路径。

项目定位:一个展示 Accelerate 全缓存策略的名言生成器

accelerate/svelte-starter的核心是一个名言生成器(quote generator):它从预置的名言数据集中检索最新添加的一条名言,分别以"启用缓存"和"不启用缓存"两种方式返回,从而让开发者直观对比不同缓存策略下的表现。项目在 SvelteKit 应用中同时使用了 Prisma ORM 与 Prisma Accelerate,并在 API 路由 中演示了 Accelerate 提供的每一种缓存策略。

名言生成器的工作流程可以拆解为三个环节:

  • 获取名言(Fetch a quote):检索最近添加的名言,既支持开启缓存,也支持关闭缓存;
  • 应用缓存策略(Apply caching strategy):根据请求参数选择不同的缓存策略,包括 TTL、SWR、TTL+SWR,或者完全不用缓存;
  • 返回名言(Return the quote):返回选中的名言,同时附带缓存状态等元数据(cache status、命中区域、耗时等)。

从源码结构看,这三个环节分别落在 API 路由(策略解析与分发)、查询封装(执行查询并附带 Accelerate 信息)以及 前端组件(元数据可视化)中。

运行前置条件

在动手运行之前,需要准备两样东西:

  1. 数据库连接串(connection string):一个公网可访问数据库的连接串,用于建表和写入种子数据;
  2. Accelerate 连接串:包含你的Accelerate API key,可以在 Prisma Data Platform 中为项目启用 Accelerate 后获取。Accelerate 连接串的结构为:
prisma://accelerate.prisma-data.net/?api_key=__YOUR_ACCELERATE_API_KEY__

Accelerate 连接串负责在 Prisma Client 与底层数据库之间建立一条加速通道,Prisma Client 的所有查询都经由它执行,而缓存策略正是由 Accelerate 在这条通道上实现的。

完整上手指南:五步跑通示例

1. 克隆仓库并安装依赖

从镜像仓库克隆项目(--depth=1只拉取最新一次提交,加快克隆速度),进入示例目录并安装依赖:

git clone https://gitcode.com/gh_mirrors/pr/prisma-examples.git --depth=1 cd prisma-examples/accelerate/svelte-starter npm install

项目依赖由 package.json 管理,其中与本文主题直接相关的依赖包括@prisma/client、@prisma/extension-accelerate(Accelerate 扩展)、prisma(CLI),以及用于请求参数校验的zod和用于日期格式化的date-fns。

2. 配置环境变量

在项目根目录创建.env文件:

touch .env

然后写入以下内容:

# .env # Accelerate connection string (used for queries by Prisma Client) DATABASE_URL="__YOUR_ACCELERATE_CONNECTION_STRING__" VITE_PUBLIC_URL="http://localhost:5173"

其中__YOUR_ACCELERATE_CONNECTION_STRING__是占位符,需要替换为你自己的 Accelerate 连接串(结构为prisma://accelerate.prisma-data.net/?api_key=__YOUR_ACCELERATE_API_KEY__)。VITE_PUBLIC_URL用于前端浏览器环境访问 API,默认指向 Vite 开发服务器地址http://localhost:5173。

值得说明的是,DATABASE_URL在这一项目中有两处消费方:一是 prisma.config.ts 通过env("DATABASE_URL")将其作为datasource的 URL 提供给 Prisma CLI(迁移、种子等命令使用);二是 Prisma 客户端初始化 将其作为accelerateUrl传入客户端(应用运行时查询使用)。

3. 迁移建表并写入种子数据

Prisma schema 中只定义了一个Quotes模型,可以用以下命令把它映射到数据库并创建对应的Quotes表:

npx prisma migrate dev --name init

迁移完成后,数据库里会有一张空的Quotes表。接着运行种子脚本,向表中写入示例名言记录:

npx prisma db seed

种子脚本的入口在 prisma.config.ts 中声明为tsx ./prisma/seed.ts,实际执行逻辑位于 prisma/seed.ts:通过createMany批量写入 20 条经典名言,并开启skipDuplicates: true避免重复数据。

4. 生成 Prisma Client

执行以下命令生成 Prisma Client:

npx prisma generate

schema.prisma 中指定了生成器配置:provider = "prisma-client"、output = "./generated",因此生成产物位于prisma/generated目录,代码中通过prisma/generated/client导入。

5. 启动应用

npm run dev

启动后访问http://localhost:5173,即可看到"带缓存"与"不带缓存"两种方式下检索到的最近名言,以及对应的缓存统计信息。

从源码理解 Accelerate 的接入方式

数据模型:单表 Quotes

schema.prisma 中只有一个模型:

model Quotes { id Int @id @default(autoincrement()) quote String createdAt DateTime @default(now()) }

它只有三个字段:自增主键id、名言正文quote和默认取当前时间的createdAt。示例中查询"最新添加的名言"正是通过orderBy: { id: "desc" }结合take: 1实现的。

客户端初始化:accelerateUrl + withAccelerate

Prisma Client 的初始化集中在 src/lib/prisma.ts:

import { PrismaClient } from '../../prisma/generated/client' import { withAccelerate } from '@prisma/extension-accelerate' const prisma = new PrismaClient({ accelerateUrl: process.env.DATABASE_URL, }).$extends(withAccelerate()); export default prisma

关键点有两个:

  • accelerateUrl:把.env中的DATABASE_URL(即 Accelerate 连接串)传给 PrismaClient,使所有查询经由 Accelerate 转发;
  • $extends(withAccelerate()):通过扩展机制为客户端注入cacheStrategy查询参数和withAccelerateInfo()方法——前者用于声明缓存策略,后者用于取回缓存的元数据。

这一单例客户端被 query.ts 复用,保证了整个应用共享同一个带 Accelerate 扩展的连接实例。

种子数据与迁移配置

prisma.config.ts 完整承担了 Prisma 7 时代的配置职责:

export default defineConfig({ schema: "prisma/schema.prisma", migrations: { path: "prisma/migrations", seed: "tsx ./prisma/seed.ts", }, datasource: { url: env("DATABASE_URL"), }, });
  • migrations.path指定迁移文件目录;
  • migrations.seed指定npx prisma db seed实际执行的命令;
  • datasource.url从环境变量读取数据库连接串,供migrate等 CLI 命令使用。

四种缓存策略的实现与参数

这是整个示例的核心。API 路由 src/routes/api/quotes/+server.ts 用一张映射表集中定义了四种策略:

const cacheStrategies: Record<QuoteCacheType, CacheStrategy | undefined> = { 'SWR': { swr: 30 }, 'TTL': { ttl: 30 }, 'No caching': undefined, 'TTL + SWR': { ttl: 30, swr: 60 }, };

对应的类型定义在 src/lib/types/index.ts:

export type CacheStrategy = | { ttl: number; swr: number } | { ttl: number } | { swr: number };

四种策略的含义与参数取值如下:

策略(cache参数)cacheStrategy取值行为说明
TTL{ ttl: 30 }数据在缓存中存活 30 秒;存活期内命中直接返回缓存,减少数据库压力
SWR{ swr: 30 }Stale-While-Revalidate:数据过期后的 30 秒内仍可返回旧数据,同时在后台异步刷新缓存
TTL + SWR{ ttl: 30, swr: 60 }前 30 秒为新鲜缓存,之后 60 秒内允许返回过期数据并后台重新验证
No cachingundefined不启用任何缓存,仅使用 Accelerate 的连接池能力

其中undefined的策略在 query.ts 的注释中也有明确说明:"cacheStrategycan also be undefined, which would mean only connection pooling is being used"(不传缓存策略即只使用连接池)。

请求参数的解析与校验

客户端通过 URL 查询参数?cache=TTL(或SWR、TTL + SWR、No caching)来选择策略。服务端在 GET 处理器 中完成解析与校验:

const cache = decodeURIComponent(url.searchParams.get('cache') || '') as QuoteCacheType; const parser = z.enum(["TTL", "SWR", "TTL + SWR", "No caching"]); const parsedOutput = await parser.safeParseAsync(cache); if (!parsedOutput.success) { return json({ error: 'Invalid search parameter.' }, { status: 400 }); }

这里用zod的enum校验器对参数做白名单校验:不在四种取值之内的参数会得到400错误响应。校验通过后,从映射表中取出对应的CacheStrategy,交给查询封装执行。

查询封装:cacheStrategy 与 withAccelerateInfo

实际的查询逻辑封装在 src/lib/utils/query.ts:

export const getQuotes = async (strategy?: CacheStrategy) => { const start = Date.now(); const result = await prisma.quotes .findMany({ cacheStrategy: strategy, orderBy: { id: "desc" }, take: 1, }) .withAccelerateInfo(); return { data: result?.data?.[0], info: result.info, time: Date.now() - start, }; };

三个要点:

  • cacheStrategy: strategy:把映射表算出的策略对象直接传给查询,Accelerate 据此决定缓存行为;
  • .withAccelerateInfo():查询链式调用该方法后,返回结果会附带info元数据;
  • 耗时统计:用Date.now()记录查询前后时间差,前端据此展示每次请求的实际耗时。

返回的info对应 AccelerateInfo 类型:

export type AccelerateInfo = { cacheStatus: "ttl" | "swr" | "miss" | "none"; lastModified: Date; region: string; requestId: string; signature: string; };

字段语义如下:

字段说明
cacheStatus缓存状态:ttl(TTL 命中)、swr(SWR 命中)、miss(未命中)、none(未启用缓存)
lastModified缓存内容最近一次修改的时间
region响应来自哪个 Accelerate 缓存节点区域
requestId本次请求的标识
signature请求签名

前端页面如何消费缓存接口

页面入口 src/routes/+page.svelte 在挂载时并行发起四次请求,分别对应四种缓存策略:

onMount(async () => { try { ttl = await fetchQuotes('TTL') swr = await fetchQuotes('SWR') both = await fetchQuotes('TTL + SWR') none = await fetchQuotes('No caching') } catch (error) { ... } })

四个结果通过网格布局(grid-cols-4)渲染为四张并排卡片,由 Quote.svelte 负责展示。每张卡片呈现的内容包括:名言 ID 与正文、创建时间、缓存节点区域(Cache Node Region)、缓存最近修改时间(Cached Modified at)、缓存状态(Cache status)以及请求耗时(Time taken)。

其中缓存状态做了直观的可视化:Quote.svelte 中当cacheStatus为ttl或swr时,会以绿色高亮并追加 "CACHE HIT" 字样;否则以红色显示。这使得缓存是否命中一眼可辨。

VITE_PUBLIC_URL 的双端适配

前端请求 API 时使用的地址来自 src/lib/utils/helper.ts:

export const HOST = browser ? import.meta.env.VITE_PUBLIC_URL : process.env.VITE_PUBLIC_URL;

它根据运行环境区分取值方式:浏览器端读取 Vite 暴露的import.meta.env.VITE_PUBLIC_URL,服务端则读取process.env.VITE_PUBLIC_URL,保证 SSR 与浏览器两种场景下都能拿到正确的 API 主机地址。

如何验证缓存是否生效

启动应用后,可以通过以下两个信号验证缓存策略的实际效果:

  1. 观察Cache status与命中标识:TTL/SWR 策略的卡片在缓存生效期会显示绿色 "CACHE HIT";刷新页面后,ttl、swr状态会持续出现,而miss表示该次请求穿透到了数据库。四张卡片中 "No caching" 的卡片理论上始终不会命中缓存(状态为none),可作为对照组。
  2. 对比Time taken耗时:每张卡片都会展示本次请求耗时。多次点击 "Refresh Page" 刷新页面,缓存命中时响应耗时通常会显著低于未命中时,从而直观感受到缓存对数据库负载和延迟的削减。

另外,卡片上的region(缓存节点区域)与lastModified(缓存修改时间)字段来自 Accelerate 返回的元数据,可以进一步确认请求确实经过了 Accelerate 缓存节点。

结语:沿着示例继续深入

accelerate/svelte-starter的价值在于把"Prisma ORM + SvelteKit + Accelerate 缓存"这条链路压缩成了一个最小可运行闭环:一张表、一个查询封装、一个 API 路由,就能完整覆盖 TTL、SWR、TTL+SWR 与无缓存四种模式。如果你想进一步探索:

  • 阅读 API 路由源码 理解策略分发与校验的完整逻辑;
  • 阅读 查询封装 与 类型定义 掌握cacheStrategy与AccelerateInfo的用法;
  • 查看 种子脚本 与 Schema 定义 了解数据初始化方式;
  • 仓库的 accelerate 目录下还提供了 Next.js、Nuxt、Astro、Remix 等框架的同主题 Starter,可横向对照不同框架下 Accelerate 的接入差异。
  • 示例工程

【免费下载链接】prisma-examples

🚀 Ready-to-run Prisma example projects

项目地址:https://gitcode.com/gh_mirrors/pr/prisma-examples
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询