mcpField
P
prisma-orm

prisma-orm

github.com/bobmatnyc数据与数据库78341 次安装15 周前更新
代码仓库

关于 prisma-orm

prisma-orm 是面向 TypeScript 的数据库工具参考技能,介绍模式设计、类型安全的数据访问和迁移。内容还涵盖查询、关系、事务、Prisma Studio,以及应用集成和数据库操作模式。

主要功能

  1. 01以模式优先的数据库建模
  2. 02生成类型安全的 Prisma Client
  3. 03CRUD、关系与高级查询
  4. 04开发和生产环境迁移
  5. 05事务与查询优化
  6. 06使用 Prisma Studio 可视化浏览数据

适用场景

  1. 01为 TypeScript 应用建模数据表和关系
  2. 02为应用代码生成类型安全的数据访问
  3. 03管理开发与生产环境中的模式变更
  4. 04在 Prisma Studio 中浏览、筛选和编辑记录

安装

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

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill prisma-orm

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

附带文件metadata.json

详细介绍

Prisma ORM - 类型安全的数据库工具包

面向 TypeScript 的现代数据库工具包,支持以架构为先的开发、自动生成类型安全的客户端,以及强大的迁移系统。

快速参考

安装
npm install prisma @prisma/client
npx prisma init
基本工作流
# 1. Define schema
# Edit prisma/schema.prisma

# 2. Create migration
npx prisma migrate dev --name init

# 3. Generate client
npx prisma generate

# 4. Open Studio
npx prisma studio
核心架构模式
// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

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

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

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

  @@index([authorId])
}
类型安全的 CRUD
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

// Create
const user = await prisma.user.create({
  data: {
    email: '[email protected]',
    name: 'Alice',
    posts: {
      create: { title: 'First Post', content: 'Hello World' }
    }
  },
  include: { posts: true }
});

// Read with filters
const users = await prisma.user.findMany({
  where: { email: { contains: '@example.com' } },
  include: { posts: { where: { published: true } } },
  orderBy: { createdAt: 'desc' },
  take: 10
});

// Update
await prisma.user.update({
  where: { id: userId },
  data: { name: 'Bob' }
});

// Delete
await prisma.user.delete({ where: { id: userId } });

架构设计模式

字段类型和属性
model Product {
  id          Int      @id @default(autoincrement())
  sku         String   @unique
  name        String
  description String?  // Optional field
  price       Decimal  @db.Decimal(10, 2)
  inStock     Boolean  @default(true)
  quantity    Int      @default(0)
  tags        String[] // Array field (PostgreSQL)
  metadata    Json?    // JSON field
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([sku])
  @@index([name, inStock])
}
关系

一对多:

model User {
  id    String @id @default(cuid())
  posts Post[]
}

model Post {
  id       String @id @default(cuid())
  author   User   @relation(fields: [authorId], references: [id])
  authorId String

  @@index([authorId])
}

多对多:

model Post {
  id         String     @id @default(cuid())
  categories Category[] @relation("PostCategories")
}

model Category {
  id    String @id @default(cuid())
  name  String @unique
  posts Post[] @relation("PostCategories")
}

一对一:

model User {
  id      String   @id @default(cuid())
  profile Profile?
}

model Profile {
  id     String @id @default(cuid())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
  userId String @unique
}

自关联:

model User {
  id        String @id @default(cuid())
  following User[] @relation("UserFollows")
  followers User[] @relation("UserFollows")
}

客户端操作

嵌套写入
// Create with nested relations
const user = await prisma.user.create({
  data: {
    email: '[email protected]',
    profile: {
      create: { bio: 'Software Engineer' }
    },
    posts: {
      create: [
        { title: 'Post 1', content: 'Content 1' },
        { title: 'Post 2', content: 'Content 2' }
      ]
    }
  }
});

// Update with nested operations
await prisma.user.update({
  where: { id: userId },
  data: {
    posts: {
      create: { title: 'New Post' },
      update: {
        where: { id: postId },
        data: { published: true }
      },
      delete: { id: oldPostId }
    }
  }
});
事务

顺序(交互式):

await prisma.$transaction(async (tx) => {
  const user = await tx.user.create({
    data: { email: '[email protected]' }
  });

  await tx.post.create({
    data: { title: 'Post', authorId: user.id }
  });

  // Rollback if error thrown
  if (someCondition) {
    throw new Error('Rollback transaction');
  }
});

批量(并行):

const [deletedPosts, updatedUser] = await prisma.$transaction([
  prisma.post.deleteMany({ where: { published: false } }),
  prisma.user.update({
    where: { id: userId },
    data: { name: 'Updated' }
  })
]);
高级查询

聚合:

const result = await prisma.post.aggregate({
  _count: { id: true },
  _avg: { views: true },
  _sum: { likes: true },
  _max: { createdAt: true },
  where: { published: true }
});

const grouped = await prisma.post.groupBy({
  by: ['authorId'],
  _count: { id: true },
  _avg: { views: true },
  having: { views: { _avg: { gt: 100 } } }
});

原始 SQL:

// Raw query
const users = await prisma.$queryRaw<User[]>`
  SELECT * FROM "User" WHERE email LIKE ${`%${search}%`}
`;

// Execute
await prisma.$executeRaw`
  UPDATE "Post" SET views = views + 1 WHERE id = ${postId}
`;

迁移

开发工作流
# Create and apply migration
npx prisma migrate dev --name add_user_role

# Reset database (WARNING: deletes all data)
npx prisma migrate reset

# View migration status
npx prisma migrate status
生产部署
# Apply pending migrations
npx prisma migrate deploy

# Generate client (in CI/CD)
npx prisma generate
架构原型设计
# Push schema without migrations (dev only)
npx prisma db push

# Pull schema from existing database
npx prisma db pull

集成模式

Next.js App Router
// lib/prisma.ts
import { PrismaClient } from '@prisma/client';

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

export const prisma = globalForPrisma.prisma ?? new PrismaClient();

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

服务端组件:

// app/users/page.tsx
import { prisma } from '@/lib/prisma';

export default async function UsersPage() {
  const users = await prisma.user.findMany({
    include: { posts: { take: 5 } }
  });

  return (
    <ul>
      {users.map(u => (
        <li key={u.id}>{u.name} - {u.posts.length} posts</li>
      ))}
    </ul>
  );
}

服务端操作:

// app/actions.ts
'use server';

import { prisma } from '@/lib/prisma';
import { revalidatePath } from 'next/cache';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  const authorId = formData.get('authorId') as string;

  await prisma.post.create({
    data: { title, authorId }
  });

  revalidatePath('/posts');
}
Node.js 中间件
import { PrismaClient } from '@prisma/client';
import express from 'express';

const app = express();
const prisma = new PrismaClient();

app.get('/users/:id', async (req, res) => {
  const user = await prisma.user.findUnique({
    where: { id: req.params.id },
    include: { posts: true }
  });

  if (!user) return res.status(404).json({ error: 'Not found' });
  res.json(user);
});

app.listen(3000);

性能优化

查询优化
// ❌ N+1 queries
const users = await prisma.user.findMany();
for (const user of users) {
  const posts = await prisma.post.findMany({
    where: { authorId: user.id }
  });
}

// ✅ Single query with include
const users = await prisma.user.findMany({
  include: { posts: true }
});

// ✅ Select specific fields
const users = await prisma.user.findMany({
  select: { id: true, email: true, posts: { select: { title: true } } }
});
分页
// Cursor-based (recommended for large datasets)
const posts = await prisma.post.findMany({
  take: 10,
  cursor: lastPostId ? { id: lastPostId } : undefined,
  skip: lastPostId ? 1 : 0,
  orderBy: { createdAt: 'desc' }
});

// Offset-based (simple but slower)
const posts = await prisma.post.findMany({
  skip: (page - 1) * pageSize,
  take: pageSize
});
连接池
// schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")

  // Connection pool settings
  directUrl = env("DIRECT_URL")

  // Serverless connection limit
  relationMode = "prisma" // For PlanetScale, Neon
}
# .env
DATABASE_URL="postgresql://user:pass@host:5432/db?connection_limit=10&pool_timeout=20"

Prisma Studio

# Launch visual database browser
npx prisma studio

功能:

  • 可视化数据浏览器和编辑器
  • 创建、读取、更新和删除记录
  • 筛选和搜索数据
  • 可视化查看关系
  • 运行于 localhost:5555

Prisma 与 Drizzle 对比

特性PrismaDrizzle
架构定义自定义 DSLTypeScript 代码
类型安全生成的类型推断的类型
迁移内置(migrate)drizzle-kit
查询构建器流式 API类 SQL 构建器
关系自动处理手动连接
Studio内置 GUI无 GUI
包体积~300kB~50kB
原始 SQL支持一等支持
Edge 运行时支持有限完全支持
学习曲线适中更陡峭
最适合全栈应用、快速开发、团队Edge 函数、SQL 专家、对包体积敏感的场景

选择 Prisma 的情况:

  • 团队偏好以架构为先的开发
  • 需要可视化数据库工具(Studio)
  • 希望自动处理关系
  • 构建全栈单体应用
  • 快速原型设计和迁移

选择 Drizzle 的情况:

  • 需要最小化包体积(Edge 函数)
  • 偏好类 SQL 语法
  • 部署到 Edge 运行时(Cloudflare Workers)
  • 希望完全控制 SQL 生成
  • 团队具备扎实的 SQL 专业知识

最佳实践

  1. 单例模式 - 复用 PrismaClient 实例(尤其是在开发环境中)
  2. 连接管理 - 为无服务器环境配置连接池大小
  3. 选择特定字段 - 使用 select 减少载荷大小
  4. 使用事务 - 用于需要原子性的多步操作
  5. 合理添加索引 - 在频繁查询的字段上添加 @@index
  6. 严格管理迁移 - 部署后绝不要编辑迁移
  7. 架构版本管理 - 使用具有描述性的迁移名称
  8. 软删除 - 添加 deletedAt 字段,而不是硬删除
  9. 保存前验证 - 在执行 Prisma 操作前使用 Zod 架构
  10. 监控查询 - 使用 prisma.$on('query') 记录日志

常见陷阱

❌ 创建多个 PrismaClient 实例:

// WRONG - creates connection leak
function getUser() {
  const prisma = new PrismaClient(); // New instance every call
  return prisma.user.findMany();
}

// CORRECT - singleton pattern
const prisma = new PrismaClient();
function getUser() {
  return prisma.user.findMany();
}

❌ N+1 查询:

// WRONG - multiple queries
const users = await prisma.user.findMany();
for (const user of users) {
  user.posts = await prisma.post.findMany({ where: { authorId: user.id } });
}

// CORRECT - single query with include
const users = await prisma.user.findMany({ include: { posts: true } });

❌ 多步操作缺少事务:

// WRONG - not atomic, can leave inconsistent state
await prisma.user.delete({ where: { id: userId } });
await prisma.post.deleteMany({ where: { authorId: userId } }); // May fail

// CORRECT - atomic transaction
await prisma.$transaction([
  prisma.post.deleteMany({ where: { authorId: userId } }),
  prisma.user.delete({ where: { id: userId } })
]);

危险信号

出现以下情况时请停下来重新考虑:

  • 在请求处理程序中创建新的 PrismaClient
  • 多步操作未使用事务
  • 外键或频繁查询的字段缺少索引
  • 在大型表上使用未分页的 findMany
  • 只需特定字段时却获取整个对象
  • 未处理生产环境中的连接错误
  • 在生产环境中使用 migrate dev(应使用 migrate deploy)

与其他技能的集成

  • typescript-core:Zod 验证、类型安全模式
  • nextjs-core:Server Actions、Server Components 集成
  • nextjs-v16:App Router 数据获取、缓存
  • database-migration:安全演进架构的模式

资源

相关技能

使用 Prisma 时,这些技能可提升你的工作流:

  • drizzle:Drizzle ORM,作为 Prisma 的轻量级替代方案
  • typescript:Prisma 生成类型的 TypeScript 最佳实践
  • nextjs:Prisma 与 Next.js:连接池、边缘运行时注意事项
  • test-driven-development:测试 Prisma 模型、迁移和查询

[这些技能中提供了完整文档,前提是它们已部署在你的工具包中]

评论

支持 Markdown