본문 바로가기

개발 공부

트랜잭션(Transaction)

 

트랜잭션 개념

트랜잭션(Transaction)은 여러 작업을 하나로 묶어 "전부 성공하거나 전부 실패하도록 보장하는 작업 단위"입니다.

주로 데이터베이스에서 사용되지만, SaaS 아키텍처, 프론트엔드 상태관리, 분산 시스템 등에서도 중요한 역할을 합니다.

 

 

왜 필요한가?

  • 데이터 무결성 보장
  • 중간 상태 방지 (Partial Update 문제 해결)
  • 에러 발생 시 안전하게 롤백

 

 

은행 송금 예시

A -> B에게 100만원 송금
1. A 계좌에서 100만원 차감
2. B 계좌에 100만원 입금
  • 1번 성공 후 2번 실패하면? 돈이 사라지거나 꼬일 수 있음.
  • 트랜잭션으로 묶으면 둘 다 성공 or 둘 다 실패.

 


 

ACID 속성 요약

속성 설명
A (Atomicity) 원자성: 모두 성공 or 모두 실패
C (Consistency) 일관성: 비즈니스 규칙 항상 만족
I (Isolation) 고립성: 트랜잭션끼리 간섭X
D (Durability) 지속성: 커밋된 데이터는 유지

 

 

 


 

 

Next.js에서 트랜잭션은 어떻게 적용되는가?

 

Next.js는 프론트엔드 풀스택 프레임워크이므로, 직접적인 DB 트랜잭션 로직은 주로 API Route (app/api)Server Action에서 처리합니다.

 

 

예제 Prisma에서 트랜잭션 사용하기

import { prisma } from '@/lib/prisma';

export async function transfer(userAId: number, userBId: number, amount: number) {
  const result = await prisma.$transaction(async (tx) => {
    const userA = await tx.user.update({
      where: { id: userAId },
      data: { balance: { decrement: amount } }
    });

    const userB = await tx.user.update({
      where: { id: userBId },
      data: { balance: { increment: amount } }
    });

    return { userA, userB };
  });

  return result;
}

이 방식의 장점

  • 중간 실패시 자동 rollback
  • ACID 보장
  • NestJS, Express에서도 비슷하게 사용 가능

 

 

Server Action으로 연동하기 (Next.js 14 기준)

'use server';

import { transfer } from '@/lib/transaction';

export async function transferAction(formData: FormData) {
  const from = parseInt(formData.get('from') as string);
  const to = parseInt(formData.get('to') as string);
  const amount = parseFloat(formData.get('amount') as string);

  await transfer(from, to, amount);
}
  • Next.js에서 Server Action을 쓰면 클라이언트에서 트랜잭션을 서버로 안전하게 위임 가능.

 


 

SaaS 트랜잭션 아키텍처 설계

 

SaaS에서 트랜잭션은 더 복잡하다

  • 여러 마이크로서비스 → 분산 트랜잭션 필요
  • 외부 API (결제, 배송 등) 연계 → 롤백 어려움
  • 결국 Saga 패턴이나 이벤트 기반 보상 트랜잭션으로 진화

 


1. 간단한 SaaS 트랜잭션 설계

 

예: 팀 협업 SaaS - 유저가 새 프로젝트 생성

  1. DB에 프로젝트 생성
  2. 기본 보드 생성
  3. 팀원 초대 메일 전송
  4. 로그 기록

단순 DB 트랜잭션 가능 영역

  • 프로젝트 생성 + 보드 생성 (DB 내부)

비동기 처리 영역

  • 메일 전송
  • 로그 기록

 

2. 복잡한 SaaS 트랜잭션 설계 (Event-Driven)

  1. API → Command 발행 (CreateProject)
  2. DB 트랜잭션 수행 (commit)
  3. Kafka, SNS 등으로 Event 발행
  4. Mail, Log, Analytics 등은 Event Consumer가 비동기 수행
[API]
  -> [Database Transaction]
    -> [Event Broker]
      -> [Mail Service]
      -> [Log Service]
      -> [Analytics Service]

 

 

Event-Driven Architecture?

시스템 내의 모든 동작을 '이벤트(event)' 중심으로 설계하는 아키텍처 방식입니다.

  • 어떤 일이 일어나면 → 그 일을 나타내는 이벤트를 발행
  • 다른 시스템(서비스, 컴포넌트 등)은 그 이벤트를 구독하여 처리

예시

[프로젝트 생성됨 이벤트] → 메일 전송 서비스가 감지 → 메일 발송 → 알림 서비스가 감지 → 알림 생성
  • 서비스 간 강한 결합 없이 느슨하게 연결(loose coupling)
  • 확장성과 비동기 처리에 강함

 

 

 

3. 분산 트랜잭션 대안: Saga 패턴

  • 서비스별 로컬 트랜잭션 → 각 단계마다 보상 작업 정의
  • 예: 결제 성공 → 배송 실패 → 결제 취소 (보상)
  • 장점: 시스템 확장성, 장애 복원력 ↑ 단점: 구현 복잡도 ↑

 

Saga 패턴?

분산 시스템에서 트랜잭션처럼 보장되는 '일련의 작업 흐름'을 관리하는 방법입니다.

  • 마이크로서비스 환경에서는 여러 DB에 걸친 트랜잭션이 어렵기 때문에
  • 각 서비스가 자기 영역에서 로컬 트랜잭션을 수행하고,
  • 실패 시 보상 작업(rollback과 유사)을 수행합니다

예시 (상품 주문 Saga)

  1. 주문 생성 (Order Service)
  2. 결제 요청 (Payment Service)
  3. 재고 감소 (Inventory Service)
  4. 배송 예약 (Delivery Service)

➡️ 어디서 실패하면? 이전 단계까지 보상 트랜잭션 실행

[배송 실패] → [재고 복구] → [결제 취소] → [주문 취소]

 

장점

  • 마이크로서비스 간 독립성 유지
  • 실패 처리 유연함

단점

  • 구현 복잡도 ↑
  • 각 단계마다 보상 로직 필요

 


 

 

환경 트랜잭션 전략
단일 DB (Postgres, MySQL 등) ORM의 DB 트랜잭션 활용 (Prisma, TypeORM 등)
Next.js API Route Server Action or API Route에서 트랜잭션 수행
SaaS (Microservice) Event-Driven, Saga 패턴 고려
외부 연계 시스템 포함 보상 트랜잭션 설계 필수

 

 

 

 

참고 링크

 

'개발 공부' 카테고리의 다른 글

Pub/Sub (1)  (0) 2025.06.28
Node.js, Redis  (0) 2025.06.25
MCP (Model Context Protocol) (3)  (1) 2025.06.17
MCP (Model Context Protocol) (1)  (11) 2025.06.12
$, _name$ 네이밍 컨벤션  (0) 2025.06.03