Prisma 완벽 가이드: 차세대 TypeScript ORM
이 글의 핵심
Prisma는 타입 안전하고 직관적인 차세대 ORM으로 Prisma Schema로 DB를 정의하고 자동 생성된 타입 안전 클라이언트로 쿼리합니다. 마이그레이션, Prisma Studio GUI, 강력한 관계 쿼리로 생산성이 높습니다.
Prisma란?
Prisma는 차세대 TypeScript ORM(Object-Relational Mapping)으로, 타입 안전성과 개발자 경험을 극대화한 데이터베이스 툴킷입니다.
핵심 구성 요소
-
Prisma Schema
- 선언적 데이터 모델
- 단일 진실 공급원
- 마이그레이션 생성
-
Prisma Client
- 자동 생성 쿼리 빌더
- 완벽한 타입 안전성
- 자동완성 지원
-
Prisma Migrate
- 스키마 마이그레이션
- 버전 관리
- 롤백 지원
-
Prisma Studio
- GUI 데이터 브라우저
- 데이터 편집
- 시각적 탐색
TypeORM vs Sequelize vs Prisma 비교
| 항목 | TypeORM | Sequelize | Prisma |
|---|---|---|---|
| 언어 | TypeScript | JavaScript/TS | TypeScript |
| 스키마 정의 | 데코레이터 클래스 | 모델 클래스 | Schema 파일 |
| 타입 안전성 | 좋음 | 보통 | 매우 좋음 |
| 마이그레이션 | CLI | CLI | Migrate CLI |
| Raw SQL | 지원 | 지원 | 지원 |
| 관계 쿼리 | Eager/Lazy | Include | Include |
| N+1 해결 | 수동 | 수동 | 자동 |
| GUI | ❌ | ❌ | Prisma Studio |
| 학습 곡선 | 중간 | 중간 | 낮음 |
프로젝트 설정
# Prisma 설치
npm install -D prisma
npm install @prisma/client
# Prisma 초기화
npx prisma init
# PostgreSQL 사용 시
npx prisma init --datasource-provider postgresql
# MySQL 사용 시
npx prisma init --datasource-provider mysql
디렉터리 구조
my-project/
├── prisma/
│ ├── schema.prisma # 스키마 정의
│ └── migrations/ # 마이그레이션 파일
├── src/
│ └── index.ts
├── .env # DATABASE_URL
└── package.json
Prisma 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?
role Role @default(USER)
posts Post[]
profile Profile?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([email])
@@map("users") // 테이블명 지정
}
model Profile {
id Int @id @default(autoincrement())
bio String?
userId Int @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
tags Tag[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([authorId])
@@index([published])
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}
enum Role {
USER
ADMIN
MODERATOR
}
마이그레이션
# 마이그레이션 생성 및 적용
npx prisma migrate dev --name init
# 프로덕션 적용
npx prisma migrate deploy
# 마이그레이션 상태 확인
npx prisma migrate status
# 마이그레이션 리셋 (개발 전용)
npx prisma migrate reset
# Prisma Client 재생성
npx prisma generate
Prisma Client 사용
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// Create
const user = await prisma.user.create({
data: {
email: '[email protected]',
name: '홍길동',
posts: {
create: [
{ title: '첫 번째 글' },
{ title: '두 번째 글' }
]
}
}
});
// Read
const users = await prisma.user.findMany();
const user = await prisma.user.findUnique({
where: { email: '[email protected]' }
});
// Include 관계
const userWithPosts = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: true,
profile: true
}
});
// Update
const user = await prisma.user.update({
where: { id: 1 },
data: { name: '김철수' }
});
// Delete
await prisma.user.delete({
where: { id: 1 }
});
고급 쿼리
필터링
// AND 조건
const users = await prisma.user.findMany({
where: {
AND: [
{ age: { gte: 20 } },
{ role: 'USER' }
]
}
});
// OR 조건
const users = await prisma.user.findMany({
where: {
OR: [
{ email: { contains: 'gmail.com' } },
{ email: { contains: 'naver.com' } }
]
}
});
// NOT 조건
const users = await prisma.user.findMany({
where: {
NOT: { role: 'ADMIN' }
}
});
관계 필터링
// 포스트가 있는 사용자만
const users = await prisma.user.findMany({
where: {
posts: {
some: {
published: true
}
}
}
});
// 특정 태그가 있는 포스트
const posts = await prisma.post.findMany({
where: {
tags: {
some: {
name: 'typescript'
}
}
},
include: {
author: true,
tags: true
}
});
집계
// 카운트
const userCount = await prisma.user.count();
const activeUsers = await prisma.user.count({
where: { isActive: true }
});
// 그룹화 집계
const stats = await prisma.user.groupBy({
by: ['role'],
_count: { id: true },
_avg: { age: true }
});
트랜잭션
// 연속 트랜잭션
const [user, post] = await prisma.$transaction([
prisma.user.create({ data: { email: '[email protected]' } }),
prisma.post.create({ data: { title: 'Hello' } })
]);
// 대화형 트랜잭션
await prisma.$transaction(async (tx) => {
const user = await tx.user.create({
data: { email: '[email protected]' }
});
await tx.post.create({
data: {
title: 'Hello',
authorId: user.id
}
});
// 에러 발생 시 자동 롤백
});
성능 최적화
// Select로 필요한 필드만
const users = await prisma.user.findMany({
select: {
id: true,
name: true,
email: true
}
});
// 페이지네이션
const users = await prisma.user.findMany({
skip: 10,
take: 10
});
// 커서 기반 페이지네이션
const users = await prisma.user.findMany({
take: 10,
cursor: {
id: lastUserId
},
skip: 1
});
Prisma는 현대적이고 타입 안전한 ORM입니다. 직관적인 API와 강력한 타입 시스템으로 데이터베이스 작업을 즐겁게 만듭니다.