Prisma 공부하기

2024. 10. 20. 09:59BACKEND

728x90

Prisma 공부하기

최근 이직한 이후 신생회사에서 근무하게 되었고 기술전환을 하는 과정에서 Nest.js와 Prisma를 사용하는 것으로 최종 결정 되었다, 장기적으로 좋은 부분인 것 같다. 이제 1개월이 갓 지났지만 새삼 Node 환경에서 개발을 하다보니 Spring boot환경에 비해 정말 간편하고 빠르고 뭔가 가볍다는 느낌을 많이 받는 것 같다. Prisma에 대해 공부하며 글이 정리 될 때까지 글이 계속 수정 될 것 같다.

ORM에 대하여

나는 개인적으로 JPA를 공부하며 상당히 재밌고 좋다고 느꼈다. 그런데 막상 사용하려고 하거나 실무에서 사용 할 때 주의해야 하는 부분들을 알게 되면서 러닝커브가 높고 쉽지않은 기술이라는 생각도 많이 들었다. 아마도 국내에서 JPA를 가장 잘 아는분은 김영한님이 아닐까 싶은데 김영한님은 자신의 JPA 인프런 강의에서 이런 이야기를 한다.

JPA는 쉬운 기술이 아니에요 객체지향에 대해서도 잘 알아야 하고 SQL에 대한 지식도 뛰어나야 됩니다. 배우기 쉬운 기술은 아니지만 딱 한번 열심히 공부해 놓으면 SQL 노가다로 발생하는 시간을 줄이고 비즈니스 로직을 잘 만들기 위해 고민 할 수 있는 시간이 늘어 납니다

대략 이런 이야기를 했었다. ORM을 사용하려면 많이 공부해야 하고 객체지향과 SQL에 대해서도 많이 경험하고 잘 알아야 한다는 생각에 ORM을 사용하는 것에 대해 걱정이 있었지만 결과적으로 우리팀은 앞으로 Prisma를 사용해 1~2년간 진행할 기술이전에 적용 할 계획이다.

Prisma 준비하기

npm i prisma sqlite
# prisema의 provider로 sqlite를 사용 하도록 설정한다.
npx prisma init --datasource-provider sqlite

위 코드를 실행하면 prisma라는 디렉토리가 생성되고 schema.prisma 파일이 생성되게 된다.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

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

해당 파일에는 DB에 연결하기 위한 코드가 작성되어 있다. .env 파일로 접속정보를 관리한다.

schema.prisma 파일에 스키마를 정의하고 마이그레이션을 하면 DB에 테이블이 생성되게 된다.
JPA에서는 도메인 디렉토리를 생성하고 @Domain 어노테이션으로 스키마를 정의 한 뒤 어플리케이션이 실행되며 테이블을 생성 했지만 prisma에서는 마이그레이션(테이블 생성)을 위한 코드를 실행해 주어야 한다.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

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

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

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

위 코드처럼 간략한 schema를 생성하고 shell에서 npx prisma migrate dev --name migrate-history 코드를 실행해 마이그레이션을 한다.

이미지처럼 migrations디렉토리에 migrations.sql에는 실제 어떤 SQL이 실행되었는지에 대한 내용이 저장되게 된다.
npx prisma migrate dev --name migrate-history를 입력했기 때문에 디렉토리명이 20241019020359_migrate_history로 생성되었다 이름을 변경하고 싶다면 --name 옵션 뒤에 이름을 변경하자.

개발을 진행하며 schema가 추가 되거나 필드가 변경되는 등에 변경사항이 생기는 경우 마이그레이션 버전 관리를 위한 파일을 생성해 변경되는 스키마를 작성하고 npx prisma migrate dev --name added_job_title 이렇게 실행하면 added_job_title라는 이름으로 쿼리의 실행 이력을 저장 할 수 있다. Springboot에서는 이러한 DB의 스키마 변경 관리를 위해 Flyway 라는 마이그레이션 관리툴을 사용 했는데 솔직히 그리 편하다는 느낌은 잘 안들었는데 물론 내가 관리 경험이 부족해서 일 것 같다. prisma는 자체적으로 마이그레이션 관리까지 고려한 것 같은데 잘 사용 할 수 있도록 앞으로 학습해야 할 것들이 많은 것 같다.

CRUD

CRUD를 알아보기 전에 먼저 client 라이브러리를 설치해야 한다. npm i @prisma/client

생성


import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient()

async function main() {
  let includePosts: boolean = false
  let user: Prisma.UserCreateInput

  // Check if posts should be included in the query
  if (includePosts) {
    user = {
      email: 'elsa@prisma.io',
      name: 'Elsa Prisma',
      posts: {
        create: {
          title: 'Include this post!',
        },
      },
    }
  } else {
    user = {
      email: 'elsa@prisma.io',
      name: 'Elsa Prisma',
    }
  }

  // Pass 'user' object into query
  const createUser = await prisma.user.create({ data: user })
}
main()
const createMany = await prisma.user.createMany({
  data: [
    { name: 'Bob', email: 'bob@prisma.io' },
    { name: 'Bobo', email: 'bob@prisma.io' }, // Duplicate unique key!
    { name: 'Yewande', email: 'yewande@prisma.io' },
    { name: 'Angelique', email: 'angelique@prisma.io' },
  ],
  skipDuplicates: true, // Skip 'Bobo'
})

조회

// By unique identifier
const user = await prisma.user.findUnique({
  where: {
    email: 'elsa@prisma.io',
  },
})

// By ID
const user = await prisma.user.findUnique({
  where: {
    id: 99,
  },
})

수정

const updateUser = await prisma.user.update({
  where: {
    email: 'viola@prisma.io',
  },
  data: {
    name: 'Viola the Magnificent',
  },
})
const updateUsers = await prisma.user.updateMany({
  where: {
    email: {
      contains: 'prisma.io',
    },
  },
  data: {
    role: 'ADMIN',
  },
})

삭제

const deleteUser = await prisma.user.delete({
  where: {
    email: 'bert@prisma.io',
  },
})
const deleteUsers = await prisma.user.deleteMany({
  where: {
    email: {
      contains: 'prisma.io',
    },
  },
})

delete의 경우 조건이 여러개인 경우 deleteMany를 사용해야 하므로 주의해야 한다고 한다.
내가 제대로 이해 한 것인지 모르겠는데 아마 id같은 PK값으로 삭제 할 때에는 delete()를 사용하면 되고
where에서 condition을 여러를 사용해 삭제하는 경우 deleteMany()를 사용해야 한다는 말인 것 같다.

ORM을 사용해 보았다면 쉽게 이해 할 것 같다. 특히 ORM은 간단한 CRUD를 사용할때에는 정말 편리한 것 같다.
실제 개발에서는 훨씬 다양한 쿼리를 처리 해야 하고 도메인을 어떻게 잘 정의할 것인가가 어려운 부분이지만.

내용 업데이트 중

'BACKEND' 카테고리의 다른 글

Nest.js 공부하기 (2)  (0) 2024.11.27
Nest.js 공부하기 (1)  (3) 2024.11.04
SOAP 프로토콜 사용하기  (0) 2024.05.05
SpringBoot + Next.js 프로젝트 회고  (1) 2024.01.11
SpringBoot 공부하기 2편  (1) 2024.01.09