[Next.js] 프리즈마(Prisma)를 활용하여 데이터베이스 구축하기

문지은·2024년 1월 17일
1

Next.js - App Router

목록 보기
9/20
post-thumbnail

프리즈마 라이브러리를 사용해 Next.js 에서 애플리케이션을 데이터베이스에 연결하는 방법에 대해 알아보자.

데이터베이스 엔진은 MySQL을 사용한다.

MySQL 설치

  • MySQL 홈페이지에서 각자 운영체제에 맞는 최신 버전의 MySQL 커뮤니티 서버 설치
    • 아래 캡쳐 화면은 macOS (애플 칩) 기준

  • 설치를 진행하다 보면 root 비밀번호를 설정해야하는데, root 는 마치 데이터베이스 관리자계정과 같은 것이므로 잘 기억해 두어야 한다.

  • 설치를 완료하였으면, 이제 데이터베이스를 확인하고 관리할 수 있는 도구도 필요하다.

Prisma

  • ORM, 즉 객체 관계 매핑 도구로 데이터베이스 작업을 더 쉽게 만들어준다.
  • 애플리케이션 코드와 데이터베이스 사이의 연결을 매끄럽게 한다.
  • 쿼리 전송이나 데이터 조작 과정을 추상화하고 간소화하여 준다.
  • 프리즈마에 대한 자세한 내용은 공식문서 참고

Prisma 설치

  • VSCode에서 프리즈마 확장 프로그램 설치
    • 코드 자동완성, 코드 하이라이팅, 포매팅 등의 기능 제공

  • Prisma 설치
npm install prisma
  • 설치가 완료되면, 아래 명령어를 실행해 사용가능한 prisma 명령어를 확인할 수 있다.
npx prisma

  • prisma 기본 설정 및 prisma 폴더 생성
    • 아래 명령어를 실행하면 프로젝트 내에 프리즈마라는 새폴더가 생성되고, 이 폴더 안에는 schema.prisma 라는 파일이 포함된다.
npx prisma init

  • .env 라는 환경변수 파일도 생성되는데, 여기에는 환경 변수들을 저장할 수 있게 된다.
    • 환경변수 파일은 git 에 업로드되지 않도록 gitignore 파일에 반드시 포함시켜야 한다.
    • Prisma는 기본적으로 PostgreSQL을 사용도록 작성되어 있다.
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
  • MySQL을 사용할 예정이므로, 문자열과 커넥터를 MySQL과 호환되도록 변경한다.

  • schema.prisma 파일에서 provider를 MySQL로 수정한다.
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}
  • .env 파일 DATABASE_URL 수정
    • 데이터베이스 : mysql
    • 기본 사용자 : root
    • : 다음에는 mysql 설치시 설정했던 root 사용자의 비밀번호를 입력한다.
    • 포트번호 : 3306
DATABASE_URL="mysql://root:[root비밀번호]@localhost:3306/[데이터베이스이름]"

Prisma Data Modeling

  • 만들고자 하는 애플리케이션의 핵심 요소, 즉 엔티티를 정의하는 과정
    • ex) 쇼핑몰: 제품, 고객, 장바구니, 주문 등
  • schema.prisma 파일에 엔터티들을 모델로 정의할 수 있다.

사용자 모델을 만들어보자.

  • 모델이라는 블록을 만들고, User 라는 이름을 붙인다.
    • 모델의 이름을 지정할 때는 Pascal Case를 사용해야 한다.
  • 모든 사용자는 고유한 ID 값을 가져야 한다.
    • id 필드를 Int로 설정한다.
      • 필드 또는 속성을 선택사항으로 만드려면 물음표를 추가
    • id 필드가 각 사용자를 고유하게 식별하는 필드 임을 나타내도록 아이디라는 속성(@id)를 적용
    • @default 속성을 사용하여 기본값을 설정할 수 있다.
      • 데이터베이스가 자동으로 새로운 아이디를 생성하도록 autoincrement() 함수 사용

prisma/schema.prisma

model User {
  id Int @id @default(autoincrement())
}
  • 사용자 모델에 필요한 다른 필드도 추가한다.
model User {
  id Int @id @default(autoincrement())
  email String @unique
  name String
  followers Int @default(0)
  isActive Boolean @default(true)
}
  • 이후 다음 명령어를 실행하여 프리즈마 코드를 포매팅할 수 있다.
npx prisma format

  • 현재 User 모델에서는 간단하게 Int, String, Boolean 타입만 사용했지만, 프리즈마에서는 더 복잡한 모델을 만들기 위해 다양한 유형의 데이터 타입을 제공한다.

Prisma Migration

  • 프리즈마 스키마와 데이터베이스 스키마를 동기화할 때 사용하는 프로세스
  • 다음 명령어를 실행하여 마이그레이션 파일을 생성할 수 있다.
    • MySQL을 사용하고 있으므로, 관계형 데이터베이스 명령어를 실행한다.
# 관계형 데이터베이스
npx prisma migrate dev

# NoSQL 데이터베이스
npx prisma db push
  • 마이그레이션 파일명을 작성한뒤 enter를 치면 prisma 폴더 내부에 migrations 폴더가 생성된다.
    • 폴더명 = 마이그레이션 생성 날짜 + 작성한 파일명

[오류 해결] Access denied for user 'root'@'localhost’

  • 이전에 MariaDB를 사용한 적이 있었는데 그 때 설정했던 비밀번호로 접속을 시도하는 것 같았다.

  • 이전 비밀번호가 기억이 안나서 터미널에 아래 명령어를 실행하여 mysql에 접속한 후 비밀번호를 재설정해주었다.
    • 재설정한 비밀번호로 .env 파일의 DATABASE_URL도 수정해준다.
# mysql 데이터베이스 서버에 접속
sudo mysql -uroot -p

# 비밀번호 변경
-- for MySQL
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '[새로운비밀번호]';
-- for MariaDB
ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('[새로운비밀번호]');
  • 마이그레이션 동작 확인

  • Prisma CLI는 마이그레이션을 데이터베이스에 적용한다.
    • MySQL Workbench 에서 데이터베이스에 접속하면 User 테이블이 생성된 것을 확인할 수 있다.

  • 이렇게 마이그레이션을 통해 데이터베이스 스키마를 업데이트하고 모델 변경 사항을 반영할 수 있다.
  • 모델을 변경할 때 의미있는 이름을 지정하여 마이그레이션을 생성하는 것이 중요하다.
    • 이렇게 하면 각 마이그레이션에 어떤 변경사항이 포함되었는지 쉽게 파악할 수 있어 디버깅에 용이하다.
  • 한번 모델을 수정하고 마이그레이션을 실행해보자.
    • User 모델에 registeredAt 필드 추가 (기본값 현재)

schema.prisma

model User {
  id        Int     @id @default(autoincrement())
  email     String  @unique
  name      String
  followers Int     @default(0)
  isActive  Boolean @default(true)
  registerdAt DateTime @default(now()) // 추가
}
  • Add a registeredAt field 라는 이름의 마이그레이션 생성
npx prisma migrate dev
  • 마이그레이션 생성 및 데이터베이스 변경 확인

Prisma Client

  • Prisma Client는 개발자가 복잡한 SQL 쿼리를 작성하는 대신 간결하고 직관적인 API를 사용하여 데이터베이스 작업을 수행할 수 있게 해주는 도구이다.
    • 이는 코드의 가독성을 높이고, 타입 안정성을 통해 오류를 줄이며, 특히 타입스크립트와 잘 호환되어 강력한 타입 체킹과 자동완성 기능을 제공한다.
  • Next.js 에서 데이터베이스 작업을 하기 위해서는 먼저 Prisma Client 를 생성해야 한다.
  • Prisma Client 가 설정되면 스키마에 정의된 모델에 접근할 수 있다.
    • 이 모델들을 사용하여 데이터 생성, 조회, 업데이트, 삭제 등의 작업을 수행할 수 있다.
    • ex) prisma.user.findMany : 사용자 정보 조회
    • ex) prisma.user.create : 새로운 사용자 생성
  • Prisma 폴더 안에 client.ts 파일을 생성하고 Prisma Client를 설정해보자.

/prisma/client.ts

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

// PrismaClient 의 새 인스턴스를 생성하여 prisma 객체 정의
const prisma = new PrismaClient();

export default prisma;
  • Prisma Client 는 애플리케이션 어디에서든 생성할 수 있지만, 중요한 점은 애플리케이션 내에서 단 하나의 프리즈마 클라이언트 인스턴스만 실행되어야 한다는 것이다.
    • 이는 애플리케이션 내에서 중복 인스턴스가 생성되지 않도록 하기 위함이다.
  • Next.js 에서는 Fast Refresh 때문에 소스 코드를 변경할 때 일부 모듈이 재로드 된다.
    • 개발환경에서 이로 인해 여러 개의 Prisma Client 인스턴스가 생성될 수 있으며, 이는 Error: Too many Prisma Client 를 발생시킬 수 있다.
    • Prisma 공식 문서를 보면 이 문제를 해결할 수 있는 방법을 제시해준다.

  • 해당 코드를 사용하면, 전용 namespace를 사용하여 단 하나의 Prisma Client Instance 가 사용됨을 보장할 수 있다.
    • client.ts 수정

/prisma/client.ts

import { PrismaClient } from '@prisma/client'

// 싱글톤 패턴을 사용하여 PrismaClient 인스턴스 생성
const prismaClientSingleton = () => {
  return new PrismaClient()
}

// PrismaClientSingleton 타입 정의
declare global {
  var prisma: undefined | ReturnType<typeof prismaClientSingleton>
}

const prisma = globalThis.prisma ?? prismaClientSingleton()

export default prisma

// 개발환경에서만 글로벌 객체에 PrismaClient 인스턴스 할당
// 개발환경에서 서버가 리로드될 때마다 새로운 PrismaClient 인스턴스가 생성되는 것 방지
if (process.env.NODE_ENV !== 'production') globalThis.prisma = prisma
profile
코드로 꿈을 펼치는 개발자의 이야기, 노력과 열정이 가득한 곳 🌈

0개의 댓글