Prisma 완벽 가이드 | ORM·Schema·Migration·Query·타입 안전성·실전 활용

Prisma 완벽 가이드 | ORM·Schema·Migration·Query·타입 안전성·실전 활용

이 글의 핵심

Prisma로 타입 안전한 데이터베이스 작업을 구현하는 완벽 가이드입니다. Schema 정의, Migration, CRUD, Relation, Prisma Studio까지 실전 예제로 정리했습니다.

실무 경험 공유: TypeORM에서 Prisma로 전환하면서, 타입 안전성이 향상되고 쿼리 작성 시간이 50% 단축된 경험을 공유합니다.

들어가며: “ORM이 복잡해요”

실무 문제 시나리오

시나리오 1: 타입 안전성이 부족해요
런타임 에러가 발생합니다. Prisma는 강력한 타입을 제공합니다.

시나리오 2: Migration이 어려워요
수동 작업이 필요합니다. Prisma는 자동 Migration을 지원합니다.

시나리오 3: 쿼리가 복잡해요
Raw SQL을 작성해야 합니다. Prisma는 직관적인 API를 제공합니다.


1. Prisma란?

핵심 특징

Prisma는 차세대 ORM입니다.

주요 장점:

  • 타입 안전성: 완벽한 TypeScript 지원
  • 자동 Migration: Schema 기반
  • Prisma Studio: GUI 데이터 관리
  • 직관적 API: 쿼리 작성 간편
  • 성능: 최적화된 쿼리

2. 설치 및 설정

설치

npm install prisma @prisma/client
npx prisma init

.env

DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

Schema 정의

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

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

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

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

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

Migration

npx prisma migrate dev --name init
npx prisma generate

3. CRUD 작업

Create

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

// 단일 생성
const user = await prisma.user.create({
  data: {
    email: '[email protected]',
    name: 'John',
  },
});

// 관계 포함 생성
const userWithPost = await prisma.user.create({
  data: {
    email: '[email protected]',
    name: 'Jane',
    posts: {
      create: [
        { title: 'First Post', content: 'Hello World' },
        { title: 'Second Post', content: 'Another Post' },
      ],
    },
  },
  include: {
    posts: true,
  },
});

Read

// 단일 조회
const user = await prisma.user.findUnique({
  where: { id: 1 },
});

// 다중 조회
const users = await prisma.user.findMany({
  where: {
    email: {
      contains: '@example.com',
    },
  },
  orderBy: {
    createdAt: 'desc',
  },
  take: 10,
});

// 관계 포함 조회
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: {
    posts: {
      where: { published: true },
    },
    profile: true,
  },
});

Update

// 단일 업데이트
const updatedUser = await prisma.user.update({
  where: { id: 1 },
  data: {
    name: 'John Updated',
  },
});

// 다중 업데이트
const result = await prisma.user.updateMany({
  where: {
    email: {
      contains: '@example.com',
    },
  },
  data: {
    name: 'Updated',
  },
});

Delete

// 단일 삭제
const deletedUser = await prisma.user.delete({
  where: { id: 1 },
});

// 다중 삭제
const result = await prisma.user.deleteMany({
  where: {
    email: {
      contains: '@test.com',
    },
  },
});

4. 고급 쿼리

Aggregation

const result = await prisma.post.aggregate({
  _count: { id: true },
  _avg: { authorId: true },
  _sum: { authorId: true },
  _min: { createdAt: true },
  _max: { createdAt: true },
});

Group By

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

Transaction

const [user, post] = await prisma.$transaction([
  prisma.user.create({
    data: { email: '[email protected]', name: 'John' },
  }),
  prisma.post.create({
    data: { title: 'First Post', authorId: 1 },
  }),
]);

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

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

5. Prisma Studio

npx prisma studio

기능:

  • 데이터 조회/수정
  • GUI 인터페이스
  • 관계 시각화
  • 빠른 테스트

6. 성능 최적화

Connection Pool

const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL,
    },
  },
  log: ['query', 'info', 'warn', 'error'],
});

Select 최적화

// 필요한 필드만 선택
const users = await prisma.user.findMany({
  select: {
    id: true,
    email: true,
  },
});

정리 및 체크리스트

핵심 요약

  • Prisma: 차세대 ORM
  • 타입 안전성: 완벽한 TypeScript 지원
  • Schema: 선언적 정의
  • Migration: 자동 생성
  • Prisma Studio: GUI 관리
  • 성능: 최적화된 쿼리

구현 체크리스트

  • Prisma 설치
  • Schema 정의
  • Migration 실행
  • CRUD 구현
  • Relation 설정
  • Transaction 구현
  • 성능 최적화

같이 보면 좋은 글

  • NestJS 완벽 가이드
  • Next.js App Router 가이드
  • TypeScript 완벽 가이드

이 글에서 다루는 키워드

Prisma, ORM, TypeScript, Database, PostgreSQL, MySQL, Backend

자주 묻는 질문 (FAQ)

Q. TypeORM과 비교하면 어떤가요?

A. Prisma가 타입 안전성과 DX가 더 좋습니다. TypeORM은 더 많은 기능을 제공하지만 복잡합니다.

Q. MongoDB도 지원하나요?

A. 네, MongoDB도 지원합니다. 하지만 PostgreSQL이나 MySQL이 더 권장됩니다.

Q. Raw SQL을 사용할 수 있나요?

A. 네, prisma.$queryRaw를 사용하면 가능합니다.

Q. 프로덕션에서 사용해도 되나요?

A. 네, 많은 기업에서 안정적으로 사용하고 있습니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3