mcpField
A
api-database-prisma

api-database-prisma

github.com/agents-inc数据与数据库2641 次安装2 天前更新
代码仓库

关于 api-database-prisma

面向使用 TypeScript 和 Prisma ORM 的开发者,提供类型安全查询、Schema 优先建模与迁移的实践指南。内容涵盖关联查询、事务和连接管理,并强调避免 N+1 查询及开发环境连接耗尽。

主要功能

  1. 01PrismaClient 单例与连接管理
  2. 02类型安全的 CRUD 与分页
  3. 03关联查询及 N+1 防范
  4. 04Schema 建模与声明式迁移
  5. 05嵌套写入与事务处理

适用场景

  1. 01为 TypeScript 应用建立 Prisma 数据访问层
  2. 02设计模型、关系、索引和枚举
  3. 03查询关联数据并避免 N+1
  4. 04以事务执行多项原子写入

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/agents-inc/skills --skill api-database-prisma

安装后在 Claude Code 中输入/api-database-prisma确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.yaml
reference.md
examples/
core.md
relations.md
transactions.md

详细介绍

原文在翻译后有更新,译文可能不是最新。

使用 Prisma ORM 的数据库

快速指南: 使用 Prisma ORM 执行类型安全的数据库查询,并自动生成 TypeScript 类型。采用以 Schema 为先的设计和声明式迁移。使用 include 查询关联数据,使用 $transaction 执行原子操作。开发环境中必须使用单例模式,以避免连接耗尽。在交互式事务回调中,始终使用 tx(而非 prisma)。


<critical_requirements>

重要:使用此技能前

所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入顺序、import type、命名常量)

(开发环境中必须对 PrismaClient 使用单例模式,以防止热重载导致连接耗尽)

(交互式事务回调中必须使用 tx 参数(而非 prisma),以确保原子性)

(关系查询必须使用 include 或嵌套 select——在同一个查询中获取关联数据,以避免 N+1 问题)

(所有外键关系都必须使用显式的 fields 和 references 定义 @relation)

</critical_requirements>


自动检测: prisma、@prisma/client、PrismaClient、prisma.schema、prisma migrate、findUnique、findMany、include、$transaction

适用场景:

  • 执行类型安全的数据库查询,并自动生成 TypeScript 类型
  • 采用以 Schema 为先的开发方式和声明式迁移
  • 需要强关系数据建模的应用
  • 使用 Prisma Studio GUI 快速构建原型

不适用场景:

  • 复杂查询需要原生 SQL 性能(Prisma 会带来额外开销)
  • Edge/无服务器环境要求冷启动开销极低(可考虑更轻量的 ORM)
  • 非 TypeScript 项目(无法发挥主要优势)
  • 需要对生成的 SQL 进行细粒度控制

涵盖的关键模式:

  • PrismaClient 单例(确保开发环境热重载安全)
  • 使用类型安全筛选器和分页执行 CRUD 操作
  • 使用 include 和嵌套 select 查询关联数据
  • 事务(嵌套写入、批处理、交互式事务)
  • Schema 设计(模型、关系、枚举、索引)

详细资源:


理念

Prisma ORM 提供声明式 Schema 语言,可生成类型安全的数据库客户端。Schema 是数据模型、TypeScript 类型和迁移的唯一事实来源。

核心原则:

  1. 以 Schema 为先的设计 - 在 schema.prisma 中定义模型,再生成其他所有内容
  2. 全面保障类型安全 - 所有查询都根据 Schema 完整提供类型
  3. 声明式迁移 - Schema 变更会自动生成迁移 SQL
  4. 直观的 API - 查询读起来就像英文(prisma.user.findMany())

核心模式

模式 1:PrismaClient 单例

使用单例模式,防止开发环境热重载期间连接池耗尽。否则,每次热重载都会创建一个新的 PrismaClient,并拥有自己的连接池,很快就会耗尽数据库连接。

// lib/db/client.ts
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined;
};

const createPrismaClient = () => {
  return new PrismaClient({
    log:
      process.env.NODE_ENV === "development"
        ? ["query", "error", "warn"]
        : ["error"],
  });
};

export const prisma = globalForPrisma.prisma ?? createPrismaClient();

if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}

优点: globalThis 可在热重载期间保持状态,条件式日志记录可避免在生产环境产生多余日志

有关无服务器连接模式,请参阅 examples/core.md。


模式 2:Schema 设计

定义包含关系、约束和默认值的模型。Schema 是唯一事实来源。

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  posts     Post[]
  profile   Profile?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@map("users")
}

model Post {
  id        String   @id @default(cuid())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id], onDelete: Cascade)
  authorId  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([authorId])
  @@map("posts")
}

优点: 使用 cuid() 生成抗冲突 ID,@updatedAt 自动跟踪变更,@relation 配合 onDelete: Cascade 可避免孤儿记录,在外键上使用 @@index,使用 @@map 将代码中的 PascalCase 映射为数据库表名中的 snake_case


模式 3:带类型安全筛选条件的 CRUD

所有查询都会根据你的架构进行完整类型检查。关键操作:

const DEFAULT_PAGE_SIZE = 20;
const MAX_PAGE_SIZE = 100;

// Find by unique field - returns T | null
const user = await prisma.user.findUnique({
  where: { email: "[email protected]" },
});

// Find many with filters + pagination
const users = await prisma.user.findMany({
  where: {
    role: { in: ["USER", "MODERATOR"] },
    createdAt: { gte: new Date("2024-01-01") },
  },
  orderBy: { name: "asc" },
  take: DEFAULT_PAGE_SIZE,
});

// Upsert - atomic create-or-update
const upserted = await prisma.user.upsert({
  where: { email: "[email protected]" },
  create: { email: "[email protected]", name: "Alice" },
  update: { name: "Alice Updated" },
});

优点: 类型安全的操作可在编译时捕获错误;findUnique 返回 T | null,强制处理空值;upsert 是原子操作

请参阅 examples/core.md,了解完整的 CRUD 操作、筛选和分页模式。


模式 4:关系查询

使用 include 或嵌套 select 高效获取相关数据,避免 N+1 查询。

// Include related records - single query
const userWithPosts = await prisma.user.findUnique({
  where: { id: userId },
  include: {
    posts: {
      where: { published: true },
      orderBy: { createdAt: "desc" },
      take: 10,
    },
    profile: true,
  },
});

// Select specific fields only - smaller payload
const userSummary = await prisma.user.findUnique({
  where: { id: userId },
  select: {
    id: true,
    name: true,
    posts: { select: { id: true, title: true } },
  },
});

优点: 单次查询可避免 N+1;include 会获取所有字段;select 可减少数据量。切勿针对每条记录循环查询——应改用 include 或 select。

请参阅 examples/relations.md,了解关系筛选、多对多关系、自关联、include 与 select 的比较,以及 N+1 反模式。


模式 5:事务

确保多个写入操作具有原子性。可用类型有三种:

// Nested writes - implicit transaction (cleanest for related records)
const user = await prisma.user.create({
  data: {
    email: "[email protected]",
    name: "Alice",
    profile: { create: { bio: "Developer" } },
    posts: { create: [{ title: "First Post", published: true }] },
  },
  include: { profile: true, posts: true },
});

// Interactive transaction - ALWAYS use tx, never prisma
return await prisma.$transaction(async (tx) => {
  const sender = await tx.account.update({
    where: { id: fromId },
    data: { balance: { decrement: amount } },
  });
  if (sender.balance < MINIMUM_BALANCE) throw new Error("Insufficient funds");
  return await tx.account.update({
    where: { id: toId },
    data: { balance: { increment: amount } },
  });
});

优点: 嵌套写入可用于相关记录;交互式事务支持业务逻辑,并能自动回滚。在回调中使用 prisma 而非 tx 会绕过事务上下文。

请参阅 examples/transactions.md,了解批量事务、错误处理、乐观并发和事务选项。


模式 6:连接管理

在 beforeExit 时处理 $disconnect(),以防止连接泄漏。对于无服务器环境,请通过单独的 DATABASE_URL_WITH_POOLER 环境变量使用连接池(PgBouncer、Prisma Accelerate)。

请参阅 examples/core.md,了解优雅关闭和无服务器连接模式。


<red_flags>

危险信号

高优先级问题:

  • 每次导入时都创建 PrismaClient——热重载期间会耗尽数据库连接
  • 在交互式事务中使用 prisma 而非 tx——会绕过事务上下文
  • 在循环中执行 N+1 查询——应改用 include 或 select
  • 缺少 @relation 属性——外键不明确会导致迁移错误

中优先级问题:

  • 经常用于筛选的列没有索引——随着数据增长,查询会变慢
  • 在大型表上使用偏移分页——性能会线性下降
  • 缺少 onDelete 级联操作——删除父记录时会产生孤立记录
  • 使用 include 获取所有字段,但实际只需要部分字段——应改用 select

注意事项和边缘情况:

  • createMany 不会返回创建的记录(在 PostgreSQL/CockroachDB/SQLite 上使用 createManyAndReturn)
  • updateMany 和 deleteMany 不会自动更新 @updatedAt 字段
  • 隐式多对多关系表不能包含额外字段——请使用显式联接模型
  • Json 字段的类型为 JsonValue——需要在解析边界进行运行时验证
  • Decimal 字段返回 Prisma.Decimal 类型——使用 .toNumber() 进行转换
  • 交互式事务的默认超时时间为 5 秒——使用 timeout 选项延长
  • 交互式事务会占用数据库连接——请尽量缩短事务时间
  • 未指定 orderBy 的 findFirst 会返回不确定的结果
  • 枚举变更需要通过迁移添加或删除值

</red_flags>


<critical_reminders>

重要提醒

所有代码都必须遵循 CLAUDE.md 中的项目约定

(在开发环境中,必须对 PrismaClient 使用单例模式,以防止热重载导致连接耗尽)

(在交互式事务回调中,必须使用 tx 参数(而非 prisma),以确保原子性)

(关系查询必须使用 include 或嵌套 select——在同一查询中获取关联数据,避免 N+1 问题)

(必须为所有外键关系使用显式的 fields 和 references 定义 @relation)

如果不遵循这些规则,将会耗尽数据库连接、破坏事务原子性、导致 N+1 性能问题,并造成关系定义不明确。

</critical_reminders>

评论

支持 Markdown