티스토리 뷰
Prisma 트랜잭션(Transaction) 활용법: 안전한 데이터 처리하기
데이터베이스에서 여러 개의 작업을 하나의 단위로 묶어 실행할 때 트랜잭션(Transaction)이 필요합니다.
Prisma에서는 트랜잭션을 활용하여 데이터 무결성을 보장하고, 중간에 오류가 발생하면 모든 작업을 롤백할 수 있습니다.
이번 글에서는 Prisma의 트랜잭션 기능과 함께 여러 개의 데이터 작업을 안전하게 처리하는 방법을 알아보겠습니다.
1. 트랜잭션(Transaction)이란?
트랜잭션(Transaction)은 여러 개의 데이터베이스 연산을 하나의 작업 단위로 실행하는 방식입니다.
✅ 원자성(Atomicity): 하나의 트랜잭션 내 모든 작업이 성공해야 데이터가 저장됨
✅ 일관성(Consistency): 트랜잭션이 실행되면 데이터가 항상 유효한 상태 유지
✅ 고립성(Isolation): 트랜잭션 간 간섭 없이 독립적으로 실행
✅ 지속성(Durability): 성공한 트랜잭션은 영구적으로 반영됨
👉 예제: 사용자 계정을 생성하고, 초기 포인트를 지급하는 경우
- 성공 시:
User
와Points
테이블에 데이터를 정상 추가 - 실패 시: 두 개의 작업 모두 롤백
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 트랜잭션을 활용하여 데이터 무결성을 유지하며 안전한 데이터 처리를 수행하세요!
'study > nodejs' 카테고리의 다른 글
Prisma 성능 최적화: 빠르고 효율적인 데이터베이스 관리 방법 (0) | 2025.03.14 |
---|---|
Prisma에서 관계형 데이터 모델링: 일대일, 일대다, 다대다 관계 구현 (0) | 2025.03.13 |
Prisma Migrate로 데이터베이스 스키마 관리하기 (0) | 2025.03.13 |
Prisma Client 활용법: 타입 안전한 CRUD 쿼리 작성하기 (0) | 2025.03.12 |
Prisma 시작하기: 설치부터 첫 번째 데이터베이스 연결까지 (0) | 2025.03.12 |
- Total
- Today
- Yesterday
- nodejs
- 백엔드개발
- 개발블로그
- SEO최적화
- llm
- SEO 최적화
- github
- rag
- fastapi
- 웹개발
- App Router
- LangChain
- PostgreSQL
- seo 최적화 10개
- REACT
- AI 자동화
- 프론트엔드
- nextJS
- Webpack
- kotlin
- Docker
- NestJS
- CI/CD
- Next.js
- AI챗봇
- 스마트 컨트랙트
- Ktor
- 관리자
- gatsbyjs
- Prisma
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |