跳到主要内容

如何在单个应用中使用多个数据库

15 分钟

介绍

本指南介绍如何在单个 Next.js 应用 中使用 Prisma ORM 连接多个数据库。您将学习如何连接到两个不同的 Prisma Postgres 数据库,管理迁移,并将您的应用部署到 Vercel。此方法适用于多租户应用或需要分离关注点以管理多个数据库连接的场景。

先决条件

在开始之前,请确保您已准备好以下内容:

1. 设置 Next.js 项目

在您想要的目录中,使用 create-next-app 创建一个新的 Next.js 应用:

npx create-next-app@latest my-multi-client-app

系统将提示您回答一些关于项目的问题。选择所有默认项。

信息

完整列表如下:

  • TypeScript
  • ESLint
  • Tailwind CSS
  • src 目录
  • App Router
  • Turbopack
  • 默认自定义导入别名:@/*

然后,导航到项目目录:

cd my-multi-client-app

2. 设置您的数据库和 Prisma 客户端

在本节中,您将创建两个独立的 Prisma Postgres 实例——一个用于用户数据,一个用于帖子数据。您还将配置每个实例的 Prisma schema 和环境变量。

首先,将 Prisma 安装为开发依赖项:

npm install -D prisma

安装使用 Prisma Postgres 所需的Prisma Client 扩展

npm install @prisma/extension-accelerate
信息

如果您不使用 Prisma Postgres 数据库,则不需要 @prisma/extension-accelerate 包。

您已为项目安装了所需的依赖项。

2.1. 创建一个用于存储用户数据的 Prisma Postgres 实例

通过运行以下命令,使用 Prisma Postgres 实例初始化 Prisma:

npx prisma@latest init --db
信息

如果您不使用 Prisma Postgres 数据库,请勿使用 --db 标志。而是创建两个 PostgreSQL 数据库实例,并将它们的连接 URL 作为 PPG_USER_DATABASE_URLPPG_POST_DATABASE_URL 添加到 .env 文件中。

按照提示命名您的项目并选择数据库区域。

prisma@latest init --db 命令会:

  • 将您的 CLI 连接到您的账户。如果您未登录或没有账户,浏览器将打开以引导您创建新账户或登录现有账户。
  • 创建一个 prisma 目录,其中包含用于您的数据库模型的 schema.prisma 文件。
  • 创建一个包含您的 DATABASE_URL.env 文件(例如,对于 Prisma Postgres,它应包含类似 DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=eyJhbGciOiJIUzI..." 的内容)。

prisma 文件夹重命名为 prisma-user-database

mv prisma prisma-user-database

编辑您的 .env 文件,将 DATABASE_URL 重命名为 PPG_USER_DATABASE_URL

.env
DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=eyJhbGciOiJIUzI...
PPG_USER_DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=eyJhbGciOiJIUzI...

打开 prisma-user-database/schema.prisma 文件并更新它以定义一个 User 模型。此外,设置环境变量并为生成的 Prisma Client 指定一个自定义 output 目录

prisma-user-database/schema.prisma
generator client {
provider = "prisma-client-js"
output = "../prisma-user-database/user-database-client-types"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
url = env("PPG_USER_DATABASE_URL")
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}

您的用户数据库 schema 现已准备就绪。

2.2. 创建一个用于存储帖子数据的 Prisma Postgres 实例

重复帖子数据库的初始化步骤:

npx prisma init --db

按照提示操作后,将新的 prisma 文件夹重命名为 prisma-post-database

mv prisma prisma-post-database

.env 文件中的 DATABASE_URL 变量重命名为 PPG_POST_DATABASE_URL

.env
DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=eyJhbGciOiJIUzI...
PPG_POST_DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/?api_key=eyJhbGciOiJIUzI...

编辑 prisma-post-database/schema.prisma 文件以定义一个 Post 模型。此外,更新 datasource URL 并设置一个自定义 output 目录

prisma-post-database/schema.prisma
generator client {
provider = "prisma-client-js"
output = "../prisma-post-database/post-database-client-types"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
url = env("PPG_POST_DATABASE_URL")
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
}

您的帖子数据库 schema 现已设置完成。

2.3. 添加帮助脚本并迁移 schemas

为了简化您的工作流程,将运行两个数据库的 Prisma 命令的帮助脚本添加到您的 package.json 文件中:

package.json
"script":{
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint",
"postinstall": "npx prisma generate --schema ./prisma-user-database/schema.prisma --no-engine && npx prisma generate --schema ./prisma-post-database/schema.prisma --no-engine",
"generate": "npx prisma generate --schema ./prisma-user-database/schema.prisma --no-engine && npx prisma generate --schema ./prisma-post-database/schema.prisma --no-engine",
"migrate": "npx prisma migrate dev --schema ./prisma-user-database/schema.prisma && npx prisma migrate dev --schema ./prisma-post-database/schema.prisma",
"deploy": "npx prisma migrate deploy --schema ./prisma-user-database/schema.prisma && npx prisma migrate deploy --schema ./prisma-post-database/schema.prisma",
"studio": "npx prisma studio --schema ./prisma-user-database/schema.prisma --port 5555 & npx prisma studio --schema ./prisma-post-database/schema.prisma --port 5556"
}
信息

如果您不使用 Prisma Postgres 数据库,请从上面的自定义脚本中移除 --no-engine 标志。

以下是自定义脚本的解释:

  • postinstall:在安装依赖项后立即运行,使用相应的 schema 文件为用户和帖子数据库生成 Prisma 客户端。
  • generate:手动触发为两个 schemas 生成 Prisma 客户端,确保您的客户端代码反映最新的模型。
  • migrate:在开发模式下使用 Prisma Migrate 为两个数据库应用待处理的迁移,根据 Prisma 文件中的更改更新它们的 schemas。
  • deploy:在生产环境中执行迁移,将您的在线数据库与 Prisma schemas 同步。
  • studio:同时在不同端口(用户数据库使用 5555,帖子数据库使用 5556)为两个数据库打开 Prisma Studio,用于可视化数据管理。

运行迁移:

npm run migrate

出现提示时,为每个数据库命名相应的迁移。

3. 准备应用以使用多个 Prisma 客户端

接下来,创建一个 lib 文件夹,用于存储实例化和导出 Prisma 客户端的帮助文件:

mkdir -p lib && touch lib/user-prisma-client.ts lib/post-prisma-client.ts

3.1. 实例化并导出用户数据库的 Prisma 客户端

lib/user-prisma-client.ts 文件中,添加以下代码:

lib/user-prisma-client.ts
import { PrismaClient } from "../prisma-user-database/user-database-client-types";
import { withAccelerate } from "@prisma/extension-accelerate"

const getPrisma = () => new PrismaClient().$extends(withAccelerate());

const globalForUserDBPrismaClient = global as unknown as {
userDBPrismaClient: ReturnType<typeof getPrisma>;
};

export const userDBPrismaClient =
globalForUserDBPrismaClient.userDBPrismaClient || getPrisma();

if (process.env.NODE_ENV !== "production")
globalForUserDBPrismaClient.userDBPrismaClient = userDBPrismaClient;
信息

如果您不使用 Prisma Postgres 数据库,请勿使用 withAccelerate 客户端扩展来扩展 PrismaClient

3.2. 实例化并导出帖子数据库的 Prisma 客户端

lib/post-prisma-client.ts 文件中,添加以下代码:

lib/post-prisma-client.ts
import { PrismaClient } from "../prisma-post-database/post-database-client-types";
import { withAccelerate } from "@prisma/extension-accelerate"

const getPrisma = () => new PrismaClient().$extends(withAccelerate());

const globalForPostDBPrismaClient = global as unknown as {
postDBPrismaClient: ReturnType<typeof getPrisma>;
};

export const postDBPrismaClient =
globalForPostDBPrismaClient.postDBPrismaClient || getPrisma();

if (process.env.NODE_ENV !== "production")
globalForPostDBPrismaClient.postDBPrismaClient = postDBPrismaClient;
信息

如果您不使用 Prisma Postgres 数据库,请勿使用 withAccelerate 客户端扩展来扩展 PrismaClient

4. 在 Next.js 应用中集成多个 Prisma 客户端

修改您的应用代码以从两个数据库中获取数据。按如下方式更新 app/page.tsx 文件:

app/page.tsx
import { postDBPrismaClient } from "@/lib/post-prisma-client";
import { userDBPrismaClient } from "@/lib/user-prisma-client";

export default async function Home() {
const user = await userDBPrismaClient.user.findFirst();
const post = await postDBPrismaClient.post.findFirst();

return (
<main className="min-h-screen bg-gray-50 py-12">
<div className="max-w-4xl mx-auto px-4">
<header className="mb-12 text-center">
<h1 className="text-5xl font-extrabold text-gray-900">Multi-DB Showcase</h1>
<p className="mt-4 text-xl text-gray-600">
Data fetched from two distinct databases.
</p>
</header>

<section className="mb-8 bg-white shadow-md rounded-lg p-6">
<h2 className="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">
User Data
</h2>
<pre className="whitespace-pre-wrap text-sm text-gray-700">
{user ? JSON.stringify(user, null, 2) : "No user data available."}
</pre>
</section>

<section className="bg-white shadow-md rounded-lg p-6">
<h2 className="text-2xl font-semibold text-gray-800 border-b pb-2 mb-4">
Post Data
</h2>
<pre className="whitespace-pre-wrap text-sm text-gray-700">
{post ? JSON.stringify(post, null, 2) : "No post data available."}
</pre>
</section>
</div>
</main>
);
}

4.1. 使用数据填充您的数据库

在另一个终端窗口中,运行脚本打开两个 Prisma Studio 实例,以向您的数据库添加数据:

npm run studio

这将在浏览器中打开两个窗口,一个在 http://localhost:5555,一个在 http://localhost:5556。导航到这些窗口并向两个数据库添加示例数据。

4.2. 运行开发服务器

在启动开发服务器之前,请注意,如果您使用的是 Next.js v15.2.0,请勿使用 Turbopack,因为存在一个已知问题。通过更新 package.json 文件,从您的 dev 脚本中移除 Turbopack:

package.json
"script":{
"dev": "next dev --turbopack",
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"postinstall": "npx prisma generate --schema ./prisma-user-database/schema.prisma --no-engine && npx prisma generate --schema ./prisma-post-database/schema.prisma --no-engine",
"generate": "npx prisma generate --schema ./prisma-user-database/schema.prisma --no-engine && npx prisma generate --schema ./prisma-post-database/schema.prisma --no-engine",
"migrate": "npx prisma migrate dev --schema ./prisma-user-database/schema.prisma && npx prisma migrate dev --schema ./prisma-post-database/schema.prisma",
"deploy": "npx prisma migrate deploy --schema ./prisma-user-database/schema.prisma && npx prisma migrate deploy --schema ./prisma-post-database/schema.prisma",
"studio": "npx prisma studio --schema ./prisma-user-database/schema.prisma --port 5555 & npx prisma studio --schema ./prisma-post-database/schema.prisma --port 5556"
}

在另一个终端窗口中,运行以下命令启动开发服务器:

npm run dev

导航到 http://localhost:3000 以查看您的 Next.js 应用显示来自两个数据库的数据:

App displaying data by querying two separate database instances

恭喜!您的 Next.js 应用现已运行,并使用两个 Prisma 客户端实例查询不同的数据库。

5. 将使用多个数据库的 Next.js 应用部署到 Vercel

按照以下步骤部署您的应用:

  1. 确保您的项目已进行版本控制并推送到 GitHub 仓库。如果您还没有仓库,请在GitHub 上创建一个。仓库准备就绪后,运行以下命令:
    git add .
    git commit -m "Initial commit with Prisma Postgres integration"
    git branch -M main
    git remote add origin https://github.com/<your-username>/<repository-name>.git
    git push -u origin main
    注意

    <your-username><repository-name> 替换为您的 GitHub 用户名和仓库名称。

  2. 登录到Vercel 并导航到您的仪表盘
  3. 创建一个新项目。按照 Vercel 的导入现有项目 指南,但在您单击 Deploy 之前,请在步骤 3 停止,您将在该步骤配置环境变量。
  4. 配置 DATABASE_URL 环境变量
    1. 展开 Environment variables 部分。
    2. 添加 PPG_USER_DATABASE_URL 环境变量
      • 键 (Key): PPG_USER_DATABASE_URL
      • 值 (Value): 粘贴您的用户数据库连接 URL,例如从项目中的 .env 文件复制。
    3. 添加 PPG_POST_DATABASE_URL 环境变量
      • 键 (Key): PPG_POST_DATABASE_URL
      • 值 (Value): 粘贴您的帖子数据库连接 URL,例如从项目中的 .env 文件复制。
    警告

    未设置环境变量之前请勿部署。如果应用无法连接到数据库,部署将失败。

  5. 单击 Deploy 按钮。Vercel 将构建您的项目并将其部署到实时 URL。

打开 Vercel 提供的实时 URL,验证您的应用是否正常工作。

恭喜!您已成功部署一个使用多个 Prisma 客户端查询两个不同数据库的应用,该应用现已在 Vercel 上上线并全面运行。

后续步骤

在本指南中,您学习了如何在单个 Next.js 应用中,使用 Prisma ORM 来连接多个数据库,具体方法包括:

  • 为用户和帖子数据库设置单独的 Prisma schemas。
  • 配置自定义 output 目录和环境变量。
  • 创建帮助脚本来生成和迁移每个 schema。
  • 实例化多个 Prisma 客户端并将它们集成到您的应用中。
  • 将您的多数据库应用部署到 Vercel。

这种方法可以帮助您保持数据模型的清晰分离,并简化多租户或多数据库场景。

为了进一步改进项目管理,可以考虑使用 monorepo 设置。查看我们的相关指南:


与 Prisma 保持联系

通过加入我们的活跃社区,继续您的 Prisma 之旅。保持关注,积极参与,并与其他开发者协作: 我们的活跃社区

我们真心珍视您的参与,期待您成为我们社区的一员!