티스토리 뷰

반응형

Prisma 트랜잭션(Transaction) 활용법: 안전한 데이터 처리하기

데이터베이스에서 여러 개의 작업을 하나의 단위로 묶어 실행할 때 트랜잭션(Transaction)이 필요합니다.
Prisma에서는 트랜잭션을 활용하여 데이터 무결성을 보장하고, 중간에 오류가 발생하면 모든 작업을 롤백할 수 있습니다.

이번 글에서는 Prisma의 트랜잭션 기능과 함께 여러 개의 데이터 작업을 안전하게 처리하는 방법을 알아보겠습니다.


1. 트랜잭션(Transaction)이란?

트랜잭션(Transaction)은 여러 개의 데이터베이스 연산을 하나의 작업 단위로 실행하는 방식입니다.
원자성(Atomicity): 하나의 트랜잭션 내 모든 작업이 성공해야 데이터가 저장됨
일관성(Consistency): 트랜잭션이 실행되면 데이터가 항상 유효한 상태 유지
고립성(Isolation): 트랜잭션 간 간섭 없이 독립적으로 실행
지속성(Durability): 성공한 트랜잭션은 영구적으로 반영됨

👉 예제: 사용자 계정을 생성하고, 초기 포인트를 지급하는 경우

  • 성공 시: UserPoints 테이블에 데이터를 정상 추가
  • 실패 시: 두 개의 작업 모두 롤백

2. Prisma 트랜잭션 기본 사용법

트랜잭션을 사용하지 않는 경우 (문제 발생 가능)

const user = await prisma.user.create({
  data: { name: "Alice", email: "alice@example.com" }
});

const point = await prisma.points.create({
  data: { userId: user.id, points: 1000 }
});

💥 문제점:

  • 첫 번째 user.create()가 성공했지만, 두 번째 points.create()에서 오류 발생 시 사용자 데이터가 이미 저장됨
  • 데이터 불일치 문제 발생 가능 (ex: 포인트 지급이 되지 않음)

3. prisma.$transaction()을 활용한 트랜잭션 적용

반응형

Prisma의 $transaction()을 사용하면 여러 개의 작업을 한 번에 실행하고, 중간에 오류가 발생하면 자동으로 롤백됩니다.

트랜잭션 적용 예제

const result = await prisma.$transaction([
  prisma.user.create({
    data: { name: "Alice", email: "alice@example.com" }
  }),
  prisma.points.create({
    data: { userId: 1, points: 1000 }
  })
]);
console.log(result);

트랜잭션이 적용되면:

  • 두 개의 작업이 모두 성공해야 데이터가 저장됨
  • 중간에 하나라도 실패하면 모든 작업이 롤백됨

4. 비동기 함수와 함께 Prisma 트랜잭션 사용

다중 데이터 삽입 트랜잭션 예제

async function createUserWithPoints(name, email, initialPoints) {
  return await prisma.$transaction(async (tx) => {
    const user = await tx.user.create({
      data: { name, email }
    });

    const points = await tx.points.create({
      data: { userId: user.id, points: initialPoints }
    });

    return { user, points };
  });
}

// 실행
createUserWithPoints("Bob", "bob@example.com", 500)
  .then(console.log)
  .catch(console.error);

설명:

  • $transaction(async (tx) => { ... })을 사용하면 비동기 함수 내에서 안전하게 트랜잭션을 실행
  • tx.user.create()tx.points.create()하나의 트랜잭션으로 처리
  • 오류 발생 시 자동 롤백

5. 트랜잭션과 동시성 제어

트랜잭션을 사용할 때 다른 트랜잭션과의 충돌을 방지하는 방법이 필요합니다.

낙관적 락(Optimistic Locking) 사용 예제

async function updateUserPoints(userId, addedPoints) {
  return await prisma.$transaction(async (tx) => {
    const userPoints = await tx.points.findUnique({
      where: { userId }
    });

    if (!userPoints) throw new Error("포인트 기록이 존재하지 않습니다.");

    return await tx.points.update({
      where: { userId },
      data: { points: userPoints.points + addedPoints }
    });
  });
}

// 실행
updateUserPoints(1, 500)
  .then(console.log)
  .catch(console.error);

설명:

  • 먼저 findUnique()를 통해 현재 포인트 값을 조회
  • 기존 값을 기반으로 업데이트하여 데이터 정합성을 유지
  • 중간에 다른 프로세스가 값을 변경할 경우 트랜잭션이 실패하고 롤백

6. Prisma 트랜잭션과 성능 최적화

대량의 데이터 삽입(예: CSV 업로드) 시 성능을 높이려면 batch insert를 고려할 수 있습니다.

대량 삽입 최적화 트랜잭션 예제

async function bulkInsertUsers(users) {
  return await prisma.$transaction(
    users.map(user => prisma.user.create({ data: user }))
  );
}

// 실행
bulkInsertUsers([
  { name: "Charlie", email: "charlie@example.com" },
  { name: "David", email: "david@example.com" }
])
  .then(console.log)
  .catch(console.error);

장점:

  • $transaction()을 사용하여 한 번에 여러 개의 데이터를 삽입
  • 중간에 오류가 발생하면 전체 작업이 롤백
  • 성능 향상: 개별 SQL 실행보다 배치 쿼리를 통해 성능이 더 향상됨

7. 트랜잭션 롤백 및 재시도 전략

트랜잭션이 실패할 경우 자동 재시도(Retry) 메커니즘을 도입할 수도 있습니다.

재시도 전략을 포함한 트랜잭션 예제

async function safeTransaction(transactionFunc, retries = 3) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      return await transactionFunc();
    } catch (error) {
      console.warn(`트랜잭션 실패, 재시도 중... (${attempt}/${retries})`);
      if (attempt === retries) throw error;
    }
  }
}

// 실행 예제
safeTransaction(() => createUserWithPoints("Eve", "eve@example.com", 700))
  .then(console.log)
  .catch(console.error);

설명:

  • 트랜잭션이 실패하면 최대 3번까지 재시도
  • 경쟁 상태(Race Condition) 해결 가능
  • 데이터 충돌이 잦은 환경에서 트랜잭션 안정성을 높이는 전략

8. 결론

Prisma에서 $transaction()을 활용하면 안전한 데이터 처리 및 무결성 보장이 가능합니다.
단순한 트랜잭션: $transaction([query1, query2])
비동기 트랜잭션: $transaction(async (tx) => { ... })
성능 최적화: batch insert 및 대량 데이터 처리
재시도(Retry) 전략: 실패 시 자동 재시도하여 안정성 향상

🚀 이제 Prisma 트랜잭션을 활용하여 데이터 무결성을 유지하며 안전한 데이터 처리를 수행하세요!

 

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함
반응형