本页将向您展示如何在 OpenNext 中设置一些流行的数据库 ORM 库。在 Cloudflare Workers 中使用这些库时有一些细微之处需要注意,我们将在此涵盖这些内容。
如果您遇到特定库的问题,请在 OpenNext GitHub 仓库 (opens in a new tab) 上提交 issue。
Drizzle ORM
Drizzle (opens in a new tab) 是一个用于 SQL 数据库的 TypeScript ORM。它旨在轻量且易于使用,是 Cloudflare Workers 的绝佳选择。 在 Drizzle 中没有太多特定配置,但有一件重要的事情需要注意,那就是不要使用全局客户端。
lib/db.ts
不要创建全局客户端,您应该为每个请求创建一个新的客户端。这是因为某些适配器(如 Postgres)会使用连接池,并为多个请求重用相同的连接。这在 Cloudflare Workers 中是不允许的,会导致后续请求失败。
PostgreSQL
不要这样做:
//lib/db.ts
import { drizzle } from "drizzle-orm/node-postgres";
import * as schema from "./schema/pg";
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.PG_URL,
});
export const db = drizzle({ client: pool, schema });您应该这样做:
//lib/db.ts
import { drizzle } from "drizzle-orm/node-postgres";
// 您可以使用 react 中的 cache 在同一请求期间缓存客户端
// 这不是强制性的,仅对服务器组件有效
import { cache } from "react";
import * as schema from "./schema/pg";
import { Pool } from "pg";
export const getDb = cache(() => {
const pool = new Pool({
connectionString: process.env.PG_URL,
// 您不希望为多个请求重用相同的连接
maxUses: 1,
});
return drizzle({ client: pool, schema });
});D1 示例
import { getCloudflareContext } from "@opennextjs/cloudflare";
import { drizzle } from "drizzle-orm/d1";
import { cache } from "react";
import * as schema from "./schema/d1";
export const getDb = cache(() => {
const { env } = getCloudflareContext();
return drizzle(env.MY_D1, { schema });
});
// 这是用于静态路由的(即 ISR/SSG)
export const getDbAsync = cache(async () => {
const { env } = await getCloudflareContext({ async: true });
return drizzle(env.MY_D1, { schema });
});Hyperdrive 示例
import { getCloudflareContext } from "@opennextjs/cloudflare";
import { drizzle } from "drizzle-orm/node-postgres";
import { cache } from "react";
import * as schema from "./schema/pg";
import { Pool } from "pg";
export const getDb = cache(() => {
const { env } = getCloudflareContext();
const connectionString = env.HYPERDRIVE.connectionString;
const pool = new Pool({
connectionString,
// 您不希望为多个请求重用相同的连接
maxUses: 1,
});
return drizzle({ client: pool, schema });
});
// 这是用于静态路由的(即 ISR/SSG)
export const getDbAsync = cache(async () => {
const { env } = await getCloudflareContext({ async: true });
const connectionString = env.HYPERDRIVE.connectionString;
const pool = new Pool({
connectionString,
// 您不希望为多个请求重用相同的连接
maxUses: 1,
});
return drizzle({ client: pool, schema });
});然后您可以使用 getDb 函数为每个请求获取一个新的客户端。这将确保您不会遇到任何连接池问题。
Prisma ORM
Prisma (opens in a new tab) 是一个流行的 Node.js 和 TypeScript ORM。它旨在易于使用,并提供许多开箱即用的功能。但是,在 Cloudflare Workers 中使用 Prisma 时有一些细微之处需要注意。
schema.prisma
在 OpenNext 中使用 Prisma 时,不要为生成的客户端提供输出目录。
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}这是因为生成的客户端需要由 OpenNext 修补才能与 Cloudflare Workers 一起工作。如果您提供了输出目录,OpenNext 将无法修补客户端,它将无法工作。
next.config.ts
因为 Prisma 有一些针对 Cloudflare Workers 的特定导出,您需要将以下内容添加到您的 next.config.ts 文件中:
const nextConfig: NextConfig = {
serverExternalPackages: ["@prisma/client", ".prisma/client"],
};这样做可以确保生成的客户端和 Prisma 客户端都包含在 workerd 运行时的构建中。
lib/db.ts
不要创建全局客户端,您应该为每个请求创建一个新的客户端。这是因为某些适配器(如 Postgres)会使用连接池,并为多个请求重用相同的连接。这在 Cloudflare Workers 中是不允许的,会导致后续请求失败。
D1 示例
不要这样做:
//lib/db.ts
import { getCloudflareContext } from "@opennextjs/cloudflare";
import { PrismaClient } from "@prisma/client";
import { PrismaD1 } from "@prisma/adapter-d1";
const { env } = getCloudflareContext();
const adapter = new PrismaD1(env.MY_D1);
export const db = new PrismaClient();您应该这样做:
//lib/db.ts
import { getCloudflareContext } from "@opennextjs/cloudflare";
// 您可以使用 react 中的 cache 在同一请求期间缓存客户端
// 这不是强制性的,仅对服务器组件有效
import { cache } from "react";
import { PrismaClient } from "@prisma/client";
import { PrismaD1 } from "@prisma/adapter-d1";
export const getDb = cache(() => {
const { env } = getCloudflareContext();
const adapter = new PrismaD1(env.MY_D1);
return new PrismaClient({ adapter });
});
// 如果您需要在静态路由(即 ISR/SSG)中访问 `getCloudflareContext`,您应该使用 `getCloudflareContext` 的异步版本来获取上下文。
export const getDbAsync = async () => {
const { env } = await getCloudflareContext({ async: true });
const adapter = new PrismaD1(env.MY_D1);
const prisma = new PrismaClient({ adapter });
return prisma;
};然后您可以使用 getDb 函数为每个请求获取一个新的客户端。这将确保您不会遇到任何连接池问题。
PostgreSQL
您也可以将 Prisma 与 PostgreSQL 一起使用。设置与上面的 D1 设置类似,但您需要使用 PrismaPostgres 适配器而不是 PrismaD1 适配器。
import { cache } from "react";
import { PrismaClient } from "@prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
export const getDb = cache(() => {
const connectionString = process.env.PG_URL ?? "";
const adapter = new PrismaPg({ connectionString, maxUses: 1 });
const prisma = new PrismaClient({ adapter });
return prisma;
});然后您可以使用 getDb 函数为每个请求获取一个新的客户端。这将确保您不会遇到任何连接池问题。
Hyperdrive
您也可以将 Prisma 与 Hyperdrive 一起使用。设置与上面的 PostgreSQL 设置类似。
//lib/db.ts
import { getCloudflareContext } from "@opennextjs/cloudflare";
// 您可以使用 react 中的 cache 在同一请求期间缓存客户端
// 这不是强制性的,仅对服务器组件有效
import { cache } from "react";
import { PrismaClient } from "@prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
export const getDb = cache(() => {
const { env } = getCloudflareContext();
const connectionString = env.HYPERDRIVE.connectionString;
const adapter = new PrismaPg({ connectionString, maxUses: 1 });
return new PrismaClient({ adapter });
});
// 这是用于静态路由的(即 ISR/SSG)
export const getDbAsync = async () => {
const { env } = await getCloudflareContext({ async: true });
const connectionString = env.HYPERDRIVE.connectionString;
const adapter = new PrismaPg({ connectionString, maxUses: 1 });
return new PrismaClient({ adapter });
};