5. Prisma
지난주에는 관계형 데이터베이스와 PostgreSQL의 기본 개념을 공부하고 SQL을 직접 작성했습니다.
이번 주에는 ORM과 Prisma의 사용 방법을 공부하고, Restaurant CRUD API의 저장소를 배열에서 PostgreSQL로 교체해보도록 하겠습니다!
공부할 내용 📚
1. Prisma
ORM은 객체와 관계형 데이터베이스의 데이터를 연결하여 애플리케이션 코드에서 데이터베이스를 다룰 수 있도록 도와주는 도구입니다. ORM의 개념과 Prisma가 어떤 역할을 하는지 알아봅니다.
- ORM이 뭘까?: ORM의 개념과 장단점을 가볍게 살펴보세요.
- Is Prisma an ORM?: Prisma ORM의 구성 요소와 일반적인 ORM과의 차이를 살펴보세요.
이어서 Prisma의 주요 기능을 공부합니다.
- Prisma Schema
- Model과 Field
- Migration
- Prisma Client
- CRUD
- Relation Query
아래 Prisma 공식 문서를 읽어보세요.
- Prisma Schema: Prisma Schema의 전체 구성과
datasource,generator, data model의 역할을 살펴보세요. - Data modeling: Model과 Field가 애플리케이션의 객체와 데이터베이스의 Table, Column에 어떻게 대응하는지 살펴보세요.
- Relations: Prisma Schema에서 1:N Relation과 Foreign Key를 표현하는 방법을 살펴보세요.
- Prisma Migrate: Prisma Schema의 변경 사항을 데이터베이스에 반영하고 변경 이력을 관리하는 방법을 살펴보세요.
- Prisma Client: Prisma Schema를 기반으로 생성된 Prisma Client를 통해 데이터베이스에 접근하는 방법을 살펴보세요.
- CRUD: Prisma Client를 사용하여 데이터를 생성, 조회, 수정, 삭제하는 방법을 살펴보세요.
- Relation queries:
select,include와 중첩 쿼리를 사용하여 관계가 있는 데이터를 다루는 방법을 살펴보세요.
2. Database 활용
데이터베이스를 애플리케이션에서 사용할 때 알아야 할 다음 개념을 공부합니다.
- Transaction
- Index
- N + 1 문제
아래 자료를 참고하거나 필요한 내용을 자유롭게 검색하여 학습해보세요!
- 트랜잭션이란?: Transaction이 필요한 이유와 Commit, Rollback, ACID의 의미를 중심으로 살펴보세요. Savepoint, Trigger, Lock은 가볍게 읽거나 넘어가도 됩니다.
- Transactions: Prisma에서 여러 데이터베이스 작업을 하나의 Transaction으로 처리하는 방법을 살펴보세요.
- Index란?: Index가 조회 성능을 높이는 원리와 사용에 따른 장단점을 살펴보세요.
- N + 1 문제란 무엇일까?:
N+1 문제의 문제점까지 읽으며 N + 1개의 쿼리가 발생하는 과정과 성능에 미치는 영향을 살펴보세요. 해결 방법은 JPA를 기준으로 설명하므로 넘어가고, Prisma에서의 해결 방법은 아래 공식 문서를 참고하세요. - Query optimization: Prisma에서
include,in등을 사용하여 N + 1 문제를 방지하는 방법을 살펴보세요.
프로젝트 실습 🎈
지난번에 구현한 Restaurant CRUD API의 저장소를 배열에서 PostgreSQL과 Prisma로 교체합니다. Controller의 요청과 응답 형식은 유지하고, Service가 Prisma Client를 통해 데이터를 관리하도록 수정해보세요.
1. 실습 환경 준비
Docker가 설치되어 있지 않다면 먼저 Docker 설치 가이드 를 참고하여 설치합니다.
프로젝트의 Root 디렉터리에 docker-compose.yml을 생성하고 다음 내용을 작성합니다.
- 아래 파일의 자세한 내용이 궁금하시다면 인프라 스터디에서 자세히 알아보세요!
services:
postgres:
image: postgres:17
container_name: restaurant-postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: restaurant
ports:
- "5432:5432"
volumes:
- restaurant_postgres_data:/var/lib/postgresql/data
volumes:
restaurant_postgres_data:다음 명령어로 PostgreSQL 컨테이너를 실행하고 상태를 확인합니다.
docker compose up -d
docker ps2. Prisma 설치 및 초기 설정
Prisma CLI와 Prisma Client를 설치하고, Schema를 작성할 prisma 폴더를 생성합니다.
pnpm add -D prisma@6.19.3
pnpm add @prisma/client@6.19.3
mkdir -p prisma프로젝트의 Root 디렉터리에 .env 파일을 생성하고 앞에서 실행한 PostgreSQL의 연결 정보를 작성합니다.
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/restaurant?schema=public"데이터베이스 연결 정보가 Git에 올라가지 않도록 .gitignore에 .env를 추가합니다.
.envprisma/schema.prisma를 생성하고 generator와 datasource를 작성합니다.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}3. Prisma Schema 작성 및 Migration
Restaurant Model을 작성하고 기존 CRUD API에서 사용한 필드를 정의합니다.
idnameaddressphone
다음 조건도 Schema에 반영하세요.
id는 Primary Key이며 자동으로 증가합니다.phone에는@unique를 적용합니다.- Restaurant와 Review의 1:N Relation을 표현합니다.
- Review에는
id,content,restaurantId를 정의합니다.
Schema를 작성한 뒤 Migration을 생성하여 PostgreSQL에 반영합니다.
pnpm exec prisma migrate dev --name init생성된 Migration의 SQL 파일을 열어 Prisma Schema가 PostgreSQL에 어떻게 반영되었는지 확인해보세요.
4. Prisma와 NestJS 연결
Prisma Client를 NestJS의 Provider로 등록하고 Restaurant Service에서 주입받아 사용합니다.
먼저 Prisma Module과 Service를 생성합니다.
pnpm exec nest generate module prisma
pnpm exec nest generate service prismaprisma.service.ts를 다음과 같이 작성합니다.
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient {}prisma.module.ts를 다음과 같이 작성합니다.
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}마지막으로 다음 작업을 진행합니다.
RestaurantModule에서PrismaModule을 불러옵니다.RestaurantService에서PrismaService를 주입받습니다.
5. Restaurant CRUD 구현
배열을 사용하던 Restaurant Service의 코드를 Prisma Client를 사용하도록 수정합니다.
- Restaurant 전체 조회
- Restaurant 단일 조회
- Restaurant 생성
- Restaurant 수정
- Restaurant 삭제
- 존재하지 않는 Restaurant를 요청했을 때
NotFoundException처리
Restaurant를 조회할 때 Review도 함께 반환하는 Relation Query를 하나 이상 작성해보세요. 반복문 안에서 각 Restaurant의 Review를 개별 조회하지 말고, N + 1 문제가 발생하지 않도록 구현합니다.
6. 동작 확인
Bruno를 사용하여 기존 Restaurant CRUD API가 PostgreSQL을 저장소로 사용해 정상적으로 동작하는지 확인합니다.
- 서버를 재시작해도 생성한 Restaurant가 유지되는지 확인합니다.
- 중복된
phone을 저장했을 때 요청이 거부되는지 확인합니다. - Restaurant와 Review를 함께 조회할 수 있는지 확인합니다.
- Prisma Studio나
psql을 사용하여 데이터가 실제 PostgreSQL에 저장되었는지 확인합니다.
pnpm exec prisma studio