트랜잭션 개념
트랜잭션(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 - 유저가 새 프로젝트 생성
- DB에 프로젝트 생성
- 기본 보드 생성
- 팀원 초대 메일 전송
- 로그 기록
단순 DB 트랜잭션 가능 영역
- 프로젝트 생성 + 보드 생성 (DB 내부)
비동기 처리 영역
- 메일 전송
- 로그 기록
2. 복잡한 SaaS 트랜잭션 설계 (Event-Driven)
- API → Command 발행 (CreateProject)
- DB 트랜잭션 수행 (commit)
- Kafka, SNS 등으로 Event 발행
- 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)
- 주문 생성 (Order Service)
- 결제 요청 (Payment Service)
- 재고 감소 (Inventory Service)
- 배송 예약 (Delivery Service)
➡️ 어디서 실패하면? 이전 단계까지 보상 트랜잭션 실행
[배송 실패] → [재고 복구] → [결제 취소] → [주문 취소]
장점
- 마이크로서비스 간 독립성 유지
- 실패 처리 유연함
단점
- 구현 복잡도 ↑
- 각 단계마다 보상 로직 필요
| 환경 | 트랜잭션 전략 |
| 단일 DB (Postgres, MySQL 등) | ORM의 DB 트랜잭션 활용 (Prisma, TypeORM 등) |
| Next.js API Route | Server Action or API Route에서 트랜잭션 수행 |
| SaaS (Microservice) | Event-Driven, Saga 패턴 고려 |
| 외부 연계 시스템 포함 | 보상 트랜잭션 설계 필수 |
참고 링크
- https://www.prisma.io/docs/concepts/components/prisma-client/transactions
- https://microservices.io/patterns/data/saga.html
- https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
'개발 공부' 카테고리의 다른 글
| 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 |