Transactions and batch queries[Prisma]

SnowCat·2023년 5월 26일
0

Prisma

목록 보기
10/10
post-thumbnail
  • 트랜젝션이란 전체가 실패하거나 성공한다는 보장이 있는 연속된 읽기, 쓰기 작업을 의미함
  • 쓰기 작업이 여러 필드에 걸쳐서 진행되는 작업이거나, updateMany와 같이 여러개의 데이터를 동시에 생성하는 경우, 또는 $transaction 명령어를 사용해 작업하는 경우 트랜젝션이 적용됨

Nested writes

  • 여러개의 필드가 관여되는 쓰기 작업의 경우 Prisma는 모든 작업이 전부 성공하는지를 알아서 확인해줌
const newUser: User = await prisma.user.create({
  data: {
    email: 'alice@prisma.io',
    posts: {
      create: [
        { title: 'Join the Prisma Slack on https://slack.prisma.io' },
        { title: 'Follow @prisma on Twitter' },
      ],
    },
  },
})

Batch/bulk operations

  • deleteMany, updateMany, createMany 메서드를 사용시 prisma는 트랜젝션하에서 동작함
await prisma.email.updateMany({
  where: {
    user: {
      id: 10,
    },
    unread: true,
  },
  data: {
    unread: false,
  },
})

$transaction API

  • transaction api는 배열을 전달하는 방법과 함수를 전달하는 2개의 방법이 있음
  • 배열을 전달하는 경우 Prisma는 배열에 주어진 순서대로 쿼리를 진행하게 됨
const [posts, totalPosts] = await prisma.$transaction([
  prisma.post.findMany({ where: { title: { contains: 'prisma' } } }),
  prisma.post.count(),
])
  • 배열을 사용할 때 Raw query를 사용할수도 잇음
const [userList, updateUser] = await prisma.$transaction([
  prisma.$queryRaw`SELECT 'title' FROM User`,
  prisma.$executeRaw`UPDATE User SET name = 'Hello' WHERE id = 2;`,
])
  • 만약 값 검증등의 문제로 인해 단순 쿼리 이상의 작업이 필요한 경우에는 Interactive transactions을 사용해 내부 함수를 통해 DB를 동작시킬 수 있음
    오류 발생시 예외를 발동시키며, Prisma는 트랜잭션을 자동으로 롤백해줌
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()

async function transfer(from: string, to: string, amount: number) {
  return await prisma.$transaction(async (tx) => {
    // 돈을 보내는 사람의 잔고를 우선 줄임
    const sender = await tx.account.update({
      data: {
        balance: {
          decrement: amount,
        },
      },
      where: {
        email: from,
      },
    })

    // 잔고값이 음수인경우 돈이 부족한경우이기때문에 쿼리를 실행하지 못하도록 막아줌
    if (sender.balance < 0) {
      throw new Error(`${from} doesn't have enough to send ${amount}`)
    }

    // 잔고값이 유효한 경우 돈을 받는 사람의 잔고값을 업데이트해줌
    const recipient = await tx.account.update({
      data: {
        balance: {
          increment: amount,
        },
      },
      where: {
        email: to,
      },
    })

    return recipient
  })
}

async function main() {
  // 가능한 쿼리
  await transfer('alice@prisma.io', 'bob@prisma.io', 100)
  // 돈이 부족해서 불가능
  await transfer('alice@prisma.io', 'bob@prisma.io', 100)
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })

출처:
https://www.prisma.io/docs/concepts/components/prisma-client/transactions

profile
냐아아아아아아아아앙

0개의 댓글