> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-vortex-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 在 ClickHouse Managed Postgres 中使用 Prisma

> 使用 Prisma ORM 将 TypeScript 应用连接到 ClickHouse Managed Postgres，通过 Prisma Migrate 执行迁移，并经由 PgBouncer 在启用证书验证的 TLS 连接上执行查询

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>Beta</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>Beta 版功能</span>
        </a>;
};

<BetaBadge link="https://clickhouse.com/cloud/postgres" galaxyTrack={true} galaxyEvent="docs.managed-postgres.guides-prisma-beta" />

[Prisma ORM](https://www.prisma.io/orm) 是一款 TypeScript ORM，提供声明式 schema、迁移工具 (Prisma Migrate) 以及自动生成的类型安全客户端。在本指南中，您将把 Prisma 连接到 ClickHouse Managed Postgres，通过迁移创建一张表，然后分别在脚本和一个简单的 HTTP 端点中查询该表。

本指南使用当前的稳定版本 Prisma ORM 7 (已在 `7.10.0` 上测试) 。

<h2 id="prerequisites">
  前置条件
</h2>

* Node.js 20.19、22.12 或 24 及以上版本
* 一个 ClickHouse Managed Postgres 服务
* [`psql`](https://www.postgresql.org/download/)，用于创建数据库。也可以在 [SQL 控制台](/zh/integrations/connectors/sql-clients/sql-console)中运行 `CREATE DATABASE` 语句。
* macOS 用户需安装 [Docker](https://docs.docker.com/get-started/get-docker/)，用于运行 Prisma Migrate (参见[运行迁移](#migrate))

<h2 id="create-service">
  创建 ClickHouse Managed Postgres 服务
</h2>

在 ClickHouse Cloud 控制台中，点击 **New service**，然后选择 **Postgres**。实例会在几分钟内准备就绪。详细操作步骤请参阅[快速入门](/zh/products/managed-postgres/quickstart)。

<h2 id="connection-details">
  获取连接信息
</h2>

在服务的左侧边栏中点击 **Connect**。弹出的对话框会显示您的用户名、密码、服务器和端口，并提供现成的连接字符串。

本指南会用到两个连接，因为 Prisma 有两个组件需要与数据库通信：

* \*\*您的应用程序 (Prisma Client) \*\*通过端口 `6432` **经由 PgBouncer** 连接。PgBouncer 负责连接池管理，使大量应用进程或 serverless 实例能够共享少量 Postgres 后端连接。
* \*\*Prisma 命令行客户端 (Prisma Migrate) \*\*通过端口 `5432` **直接**连接。Prisma Migrate 在运行期间会持有一个会话级 advisory 锁。在 PgBouncer 的事务池化模式下，该锁可能一直保留在某个池化后端连接上，而该后端随后又会为其他客户端提供服务，导致后续迁移被该锁阻塞。

在对话框顶部切换 **Directly** 和 **via PgBouncer**，即可查看各自对应的端口。两种连接的服务器和凭证相同，仅端口不同。

选中 **via PgBouncer** 时，点击 **Download CA certificate**。选中 **Directly** 时，需先开启 **Use SSL** 才会显示该按钮。下载的文件名为 `<service-name>-ca-certificate.pem`。您也可以在 **Settings → CA Certificate** 下找到该文件。此证书为您的实例所专有，用于以 `sslmode=verify-full` 模式建立连接，以确保您连接的确实是自己的服务器。

<h2 id="setup">
  设置项目
</h2>

创建一个 TypeScript 项目，并安装 Prisma 命令行客户端、Prisma Client、[node-postgres](https://node-postgres.com/) 驱动程序 adapter 和 `dotenv`：

```bash theme={null}
mkdir hello-prisma
cd hello-prisma
npm init -y
npm pkg set type=module
npm install typescript tsx @types/node @types/pg --save-dev
npm install prisma@7 --save-dev
npm install @prisma/client@7 @prisma/adapter-pg pg dotenv
```

<Note>
  请显式安装 `prisma@7` 和 `@prisma/client@7`。截至本文撰写时，npm 上 `prisma` 的 `latest` 标签指向的是 Prisma 8 的候选发布版本，其配置方式与本指南不同。
</Note>

创建 `tsconfig.json` 文件：

```json theme={null}
{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ES2023",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "types": ["node"]
  }
}
```

<Tip>
  **要集成到现有应用中？**

  请跳过 `mkdir`、`npm init` 和 `tsconfig.json` 这几步。在您的项目中运行 `npm install tsx @types/pg prisma@7 --save-dev` 和 `npm install @prisma/client@7 @prisma/adapter-pg pg dotenv`，然后从[初始化 Prisma](#init) 继续操作。
</Tip>

<h2 id="init">
  初始化 Prisma
</h2>

<Steps>
  <Step title="运行 prisma init">
    ```bash theme={null}
    npx prisma init --datasource-provider postgresql --output ../generated/prisma
    ```

    该命令会创建 `prisma/schema.prisma` 和 Prisma 配置文件 `prisma7.config.ts`，在 `.env` 中添加占位用的 `DATABASE_URL`，并将生成的客户端加入 `.gitignore` (若这两个文件不存在则会自动创建) ，同时为 AI 编程智能体添加 Prisma 技能。Prisma 7.10 及更高版本将配置文件命名为 `prisma7.config.ts`，以免与 Prisma 8 的格式冲突。
  </Step>

  <Step title="添加 CA 证书">
    将下载的 CA 证书移至项目根目录，并重命名为 `ca-certificate.pem`：

    ```bash theme={null}
    mv ~/Downloads/<service-name>-ca-certificate.pem ca-certificate.pem
    ```

    证书的相对路径会基于执行命令时所在的目录进行解析，因此请在项目根目录下运行本指南中的所有命令。
  </Step>
</Steps>

<h2 id="configure">
  配置连接
</h2>

<Steps>
  <Step title="创建数据库">
    为应用创建一个数据库。将 `<PASSWORD>` 和主机替换为 **Connect** 对话框中的值：

    ```bash theme={null}
    psql "postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/postgres?sslmode=verify-full&sslrootcert=ca-certificate.pem" -c "CREATE DATABASE guide_prisma;"
    ```

    ```text theme={null}
    CREATE DATABASE
    ```
  </Step>

  <Step title="设置连接 URL">
    在 `.env` 中，将 `prisma init` 添加的占位 `DATABASE_URL` 替换为以下两个连接 URL，二者均指向 `guide_prisma` 数据库。密码请使用 Connect 对话框中提供的密码：

    ```bash theme={null}
    # Prisma Client（你的应用）：通过 PgBouncer，端口 6432
    DATABASE_URL="postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:6432/guide_prisma?sslmode=verify-full&sslrootcert=ca-certificate.pem"

    # Prisma CLI（迁移）：直接连接，端口 5432
    DIRECT_URL="postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/guide_prisma?sslmode=require&sslaccept=strict&sslcert=ca-certificate.pem"
    ```

    由于这两个 URL 由不同的驱动程序读取，因此使用的 TLS 参数也不同：

    * **`DATABASE_URL`** 由 node-postgres 通过 `@prisma/adapter-pg` 读取。它支持标准的 `sslmode=verify-full&sslrootcert=...` 参数，与 Connect 对话框中显示的参数一致。
    * **`DIRECT_URL`** 由 Prisma 命令行客户端的 schema 引擎读取，该引擎使用自己的一套参数：`sslcert` 为 CA 证书的路径，`sslaccept=strict` 用于启用证书和主机名验证。

    <Warning>
      请勿在供 Prisma 命令行客户端使用的 URL 中使用 `sslmode=verify-full&sslrootcert=...`。schema 引擎会忽略 `sslrootcert`，并且在未设置 `sslaccept=strict` 时根本不会验证服务器证书，导致连接虽已加密，却未经身份验证。
    </Warning>
  </Step>

  <Step title="将 Prisma CLI 指向直接连接">
    替换 `prisma7.config.ts` 的内容：

    ```typescript theme={null}
    import "dotenv/config";
    import { defineConfig, env } from "prisma/config";

    export default defineConfig({
      schema: "prisma/schema.prisma",
      migrations: {
        path: "prisma/migrations",
      },
      datasource: {
        url: env("DIRECT_URL"),
      },
    });
    ```

    在 Prisma 7 中，配置文件中的 URL 仅供 CLI 使用。Prisma Client 则通过驱动程序 adapter 获取连接，该 adapter 将在[查询数据库](#query)一节中进行配置。
  </Step>
</Steps>

<h2 id="migrate">
  定义 schema 并运行迁移
</h2>

<Steps>
  <Step title="添加模型">
    在 `prisma/schema.prisma` 末尾添加一个 `Todo` 模型：

    ```prisma theme={null}
    model Todo {
      id        Int      @id @default(autoincrement())
      title     String
      done      Boolean  @default(false)
      createdAt DateTime @default(now())
    }
    ```
  </Step>

  <Step title="运行迁移">
    在 Linux 上，直接运行 Prisma Migrate：

    ```bash theme={null}
    npx prisma migrate dev --name init
    ```

    在 macOS 上，请在 Linux 容器中运行同一命令：

    ```bash theme={null}
    docker run --rm -it -v "$PWD":/app -w /app node:24 npx prisma migrate dev --name init
    ```

    <Warning>
      ClickHouse Managed Postgres 仅支持 TLS 1.3。在 macOS 上，Prisma 命令行客户端的 schema 引擎依赖系统 TLS 库，在此配置下无法建立连接，会报错 `P1011: Error opening a TLS connection: One or more parameters passed to a function were not valid`；如果移除 `sslcert`，则会报错 `bad protocol version` ([prisma/orm#29600](https://github.com/prisma/orm/issues/29600)) 。该问题仅影响需要连接数据库的命令行客户端命令，例如 `prisma migrate` 和 `prisma db pull`。Prisma Client 通过 node-postgres 进行连接，因此不受影响。在 Linux 容器中或基于 Linux 的 CI 管道中运行命令行客户端即可规避此问题。
    </Warning>

    Prisma 会在 `prisma/migrations/` 中创建 SQL 迁移文件并执行：

    ```text theme={null}
    Applying migration `20260930165244_init`

    The following migration(s) have been created and applied from new schema changes:

    prisma/migrations/
      └─ 20260930165244_init/
        └─ migration.sql

    Your database is now in sync with your schema.
    ```
  </Step>

  <Step title="生成 Prisma Client">
    ```bash theme={null}
    npx prisma generate
    ```

    客户端代码将生成到 `generated/prisma` 目录中。此命令不会连接数据库，因此可在任意平台上运行。
  </Step>
</Steps>

<h2 id="query">
  查询数据库
</h2>

<Steps>
  <Step title="创建 Prisma Client">
    创建 `lib/prisma.ts`。`PrismaPg` adapter 使用 `DATABASE_URL`，经由 PgBouncer 进行连接：

    ```typescript theme={null}
    import "dotenv/config";
    import { PrismaPg } from "@prisma/adapter-pg";
    import { PrismaClient } from "../generated/prisma/client";

    const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });

    export const prisma = new PrismaClient({ adapter });
    ```

    <Tip>
      **无需配置 PgBouncer**

      `@prisma/adapter-pg` 会将每个查询作为未命名的预处理语句发送，且从不执行 `DEALLOCATE`，因此能够兼容 PgBouncer 的事务池化模式。即使在池化的后端连接上并发运行数百个不同的查询，也不会出错。旧版 Prisma 所需的 `pgbouncer=true` URL 参数已无需设置，在使用驱动程序 adapter 时也不会产生任何作用。
    </Tip>
  </Step>

  <Step title="运行 CRUD 查询">
    创建 `script.ts`：

    ```typescript theme={null}
    import { prisma } from "./lib/prisma";

    async function main() {
      // 创建
      const todo = await prisma.todo.create({
        data: { title: "Connect Prisma to ClickHouse Managed Postgres" },
      });
      console.log("Created:", todo);

      // 读取
      const open = await prisma.todo.findMany({ where: { done: false } });
      console.log("Open todos:", open.length);

      // 更新
      const updated = await prisma.todo.update({
        where: { id: todo.id },
        data: { done: true },
      });
      console.log("Updated:", updated);

      // 删除
      await prisma.todo.delete({ where: { id: todo.id } });
      console.log("Deleted todo", todo.id);
    }

    main().finally(() => prisma.$disconnect());
    ```

    运行该脚本：

    ```bash theme={null}
    npx tsx script.ts
    ```

    ```text theme={null}
    Created: {
      id: 1,
      title: 'Connect Prisma to ClickHouse Managed Postgres',
      done: false,
      createdAt: 2026-09-30T16:52:57.116Z
    }
    Open todos: 1
    Updated: {
      id: 1,
      title: 'Connect Prisma to ClickHouse Managed Postgres',
      done: true,
      createdAt: 2026-09-30T16:52:57.116Z
    }
    Deleted todo 1
    ```
  </Step>

  <Step title="通过 HTTP 提供数据">
    创建 `server.ts`。这是一个极简的 HTTP 服务器，通过 `POST /todos` 创建待办事项，并在收到任意 `GET` 请求时返回待办事项列表：

    ```typescript theme={null}
    import { createServer } from "node:http";
    import { prisma } from "./lib/prisma";

    const port = Number(process.env.PORT ?? 3000);

    createServer(async (req, res) => {
      if (req.method === "POST" && req.url === "/todos") {
        let body = "";
        for await (const chunk of req) body += chunk;
        const todo = await prisma.todo.create({ data: { title: JSON.parse(body).title } });
        res.writeHead(201, { "Content-Type": "application/json" });
        res.end(JSON.stringify(todo));
        return;
      }

      const todos = await prisma.todo.findMany({ orderBy: { id: "asc" } });
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(JSON.stringify(todos, null, 2));
    }).listen(port, () => console.log(`Listening on http://localhost:${port}`));
    ```

    启动服务器：

    ```bash theme={null}
    npx tsx server.ts
    ```

    在另一个终端中添加两条待办事项：

    ```bash theme={null}
    curl -X POST localhost:3000/todos -H "Content-Type: application/json" -d '{"title": "Try Prisma with ClickHouse Managed Postgres"}'
    curl -X POST localhost:3000/todos -H "Content-Type: application/json" -d '{"title": "Add a read replica"}'
    ```

    在浏览器中打开 [http://localhost:3000/todos](http://localhost:3000/todos) 即可查看。响应如下：

    ```json theme={null}
    [
      {
        "id": 2,
        "title": "Try Prisma with ClickHouse Managed Postgres",
        "done": false,
        "createdAt": "2026-09-30T16:53:06.098Z"
      },
      {
        "id": 3,
        "title": "Add a read replica",
        "done": false,
        "createdAt": "2026-09-30T16:53:06.184Z"
      }
    ]
    ```
  </Step>
</Steps>

<h2 id="verify">
  在 SQL 控制台中验证
</h2>

在 ClickHouse Cloud 控制台中，打开您服务的 **SQL 控制台**，展开您的数据库及 `public` schema，然后选择 `Todo` 表。您还会看到 `_prisma_migrations` 表，Prisma Migrate 会在该表中记录已应用的迁移。

`Todo` 表中包含您通过 HTTP 端点添加的两行数据：

| id | title | done | createdAt |
| - | - | - | - |
| 2 | Try Prisma with ClickHouse Managed Postgres | false | 2026-09-30 16:53:06.098 |
| 3 | Add a read replica | false | 2026-09-30 16:53:06.184 |

<h2 id="troubleshooting">
  故障排查
</h2>

| 错误 | 原因及解决方法 |
| - | - |
| `P1011: Error opening a TLS connection: One or more parameters passed to a function were not valid` 或 `bad protocol version` | Prisma 命令行客户端运行在 macOS 上。请按照[运行迁移](#migrate)中的说明，改为在 Linux 容器中运行。 |
| `P1011: ... certificate verify failed` | Prisma 命令行客户端无法验证服务器。请确认 `DIRECT_URL` 中的 `sslcert` 指向您实例的 CA 证书。 |
| `P1011: ... cert file not found` | `DIRECT_URL` 中的 `sslcert` 路径有误。请在项目根目录下运行命令行客户端，或改用绝对路径。 |
| `unable to verify the first certificate` | Prisma Client 无法验证服务器。请确认 `DATABASE_URL` 中的 `sslrootcert` 指向您实例的 CA 证书。 |
| `ENOENT: no such file or directory` | `DATABASE_URL` 中的 `sslrootcert` 路径有误。请在项目根目录下运行应用，或改用绝对路径。 |

<h2 id="next-steps">
  后续步骤
</h2>

* [连接](/zh/products/managed-postgres/connection)：连接字符串、PgBouncer 和 TLS
* [设置](/zh/products/managed-postgres/settings)：调优 Postgres 和 PgBouncer 参数
* [只读副本](/zh/products/managed-postgres/read-replicas)：扩展读密集型工作负载
* [本地开发](/zh/products/managed-postgres/local-development)：基于 Docker 中运行的本地 Postgres 进行开发
* [在生产环境中使用 Prisma Migrate](https://www.prisma.io/docs/orm/prisma-migrate/workflows/development-and-production)：在 CI 管道中运行 `prisma migrate deploy`
