트랜잭션databaseprisma
Prisma 트랜잭션, $transaction 배열과 인터랙티브의 차이
✨ AI 요약
긴 글, 핵심만 먼저 — 이 글을 3줄로 정리해드려요.
조회 21
Prisma의 $transaction은 두 가지 형태가 있고, 둘의 동작이 꽤 다르다. 잘못 고르면 데드락이나 롱 트랜잭션으로 고생한다.
배열 형태 — 순차 배치
await prisma.$transaction([
prisma.postLike.deleteMany({ where: { postId } }),
prisma.post.delete({ where: { id: postId } }),
]);
쿼리 목록을 한 트랜잭션으로 묶는다. 중간 결과를 다음 쿼리에서 쓸 수 없다는 게 핵심 제약이다. 대신 커넥션을 잡고 있는 시간이 짧고 예측 가능하다.
인터랙티브 형태 — 콜백
await prisma.$transaction(async (tx) => {
const from = await tx.account.update({
where: { id: fromId },
data: { balance: { decrement: amount } },
});
if (from.balance < 0) throw new Error("잔액 부족");
await tx.account.update({
where: { id: toId },
data: { balance: { increment: amount } },
});
});
중간 결과로 분기할 수 있다. 대신 콜백이 끝날 때까지 커넥션과 락을 계속 잡는다. 콜백 안에서 외부 API를 호출하는 순간 그 API의 지연이 그대로 DB 락 유지 시간이 된다. 절대 하지 말자.
실무 기준
- 단순히 "다 되거나 다 안 되거나"만 필요하면 배열 형태
- 중간 값으로 검증/분기가 필요하면 인터랙티브, 단 안에서는 DB 작업만
- 인터랙티브에 timeout 옵션(기본 5초)을 명시해서 최악을 제한
pgbouncer 같은 커넥션 풀러 뒤에서는 트랜잭션 모드 설정도 확인해야 한다. 세션 기반 기능(advisory lock 등)은 풀러와 조합하면 조용히 깨진다.