Spring

Spring 트랜잭션 전파에 대해서 설명해주세요

REQUIRED부터 NESTED까지 7가지 전파 속성, rollbackOnly 함정, REQUIRES_NEW 실전 패턴. 면접에서 자주 묻는 @Transactional 전파 개념을 인터랙티브 시각화로 완벽히 준비합니다.

2026년 3월 15일 · 약 14분 읽기

Q. "@Transactional 메서드가 다른 @Transactional 메서드를 호출할 때 트랜잭션이 어떻게 전파되는지 설명해주세요."

예상 꼬리질문

답변 가이드

"트랜잭션 전파는 @Transactional 메서드가 다른 @Transactional 메서드를 호출할 때 트랜잭션을 어떻게 처리할지 결정하는 속성입니다. 기본값인 REQUIRED는 기존 트랜잭션에 참여하고, REQUIRES_NEW는 항상 독립 트랜잭션을 시작합니다."

"REQUIRED에서 가장 주의할 함정은 rollbackOnly 마킹입니다. inner()가 예외를 던지면 공유 트랜잭션에 rollbackOnly 플래그가 세워지고, outer()에서 try-catch로 예외를 잡아도 커밋 시 UnexpectedRollbackException이 발생합니다."

"REQUIRES_NEW는 감사 로그처럼 outer가 롤백되어도 독립적으로 커밋되어야 하는 경우에 사용합니다. 단, DB 커넥션을 2개 사용하므로 빈번 호출 시 커넥션 풀 고갈에 주의해야 합니다."

@Transactional 메서드 안에서 다른 @Transactional 메서드를 호출하면 트랜잭션이 어떻게 될까요? 하나의 트랜잭션으로 합쳐질까요, 아니면 별개로 실행될까요? 이 질문에 답하는 것이 트랜잭션 전파(Propagation)입니다.

이 아티클에서는 전파 속성이 필요한 이유부터 7가지 전파 속성, rollbackOnly 함정, REQUIRES_NEW 실전 패턴까지 시각화로 완전히 이해합니다.


1. 왜 전파 속성이 필요한가

꼬리질문: "트랜잭션 전파 속성이 왜 필요한지 실제 사례로 설명해주세요"

주문 생성과 감사 로그 기록이 있다고 가정합니다. 주문이 실패해서 롤백될 때 감사 로그도 같이 롤백되어야 할까요? 비즈니스 요구사항에 따라 다릅니다.

"주문 실패 기록도 남겨야 한다"면 감사 로그는 주문 트랜잭션과 독립적으로 커밋되어야 합니다. 트랜잭션 전파 속성은 이런 상황을 선언적으로 제어합니다.

트랜잭션이 전파되는 개념을 다이어그램으로 확인해 보세요.

카드를 클릭하면 inner() 실패 시 결과를 확인할 수 있습니다

REQUIRED
outer()
inner()
같은 트랜잭션
TX ━━━━━━━━━━
REQUIRES_NEW
outer()
TX #1
inner()
TX #2 (독립)

2. 7가지 전파 속성

꼬리질문: "REQUIRED와 REQUIRES_NEW의 차이를 설명해주세요"

Spring은 7가지 전파 속성을 제공합니다. 실무에서는 REQUIRED(기본값, 95%)와 REQUIRES_NEW(독립 트랜잭션)가 대부분을 차지합니다.

REQUIRED는 기존 트랜잭션이 있으면 참여하고, 없으면 새로 시작합니다. REQUIRES_NEW는 항상 새 트랜잭션을 시작하고 기존 트랜잭션은 일시 중단합니다.

각 전파 속성의 동작 방식을 표로 확인해 보세요.

행을 클릭하면 상세 설명과 코드 예시를 확인할 수 있습니다

속성명빈도
REQUIRED★★★★★
REQUIRES_NEW★★★★
SUPPORTS★★☆☆☆
NOT_SUPPORTED☆☆☆☆
MANDATORY★★☆☆☆
NEVER☆☆☆☆
NESTED★★☆☆☆

3. REQUIRED의 함정 — rollbackOnly와 UnexpectedRollbackException

꼬리질문: "rollbackOnly와 UnexpectedRollbackException이 무엇인가요?"

REQUIRED에서 가장 흔한 버그는 rollbackOnly 마킹 후 커밋 시도입니다. inner()가 RuntimeException을 던지면 Spring은 공유 트랜잭션에 rollbackOnly 플래그를 세웁니다.

outer()에서 try-catch로 예외를 잡아도 이 플래그는 지워지지 않습니다. 커밋을 시도하면 UnexpectedRollbackException이 발생합니다. 예외를 catch했으니 커밋될 것이라 예상했다면 반드시 알아야 할 함정입니다.

rollbackOnly 마킹이 발생하는 시나리오를 직접 체험해 보세요.

실행 타임라인
현재 단계 설명
"다음 단계" 버튼을 눌러 REQUIRED 전파 속성에서 발생하는 rollbackOnly 함정을 단계별로 확인하세요.

4. REQUIRES_NEW 실전 패턴

꼬리질문: "REQUIRES_NEW를 실무에서 언제 사용하나요?"

REQUIRES_NEW는 기존 트랜잭션을 일시 중단하고 새 트랜잭션을 시작합니다. 두 트랜잭션은 서로 다른 DB 커넥션을 사용하므로 완전히 독립적입니다. outer가 롤백되어도 inner의 커밋은 유지됩니다.

대표 사례는 감사 로그(Audit Log)입니다. 주문이 실패해 롤백되어도 "주문 시도 기록"은 남아야 할 때 사용합니다.

단, REQUIRES_NEW는 DB 커넥션을 2개 사용합니다. 트랜잭션 안에서 반복 호출하면 커넥션 풀이 빠르게 고갈될 수 있습니다. HikariCP 기본 풀 크기(10)와 동시 요청 수를 반드시 고려하세요.

outer 롤백 시 inner가 독립적으로 커밋되는 과정을 시뮬레이션해 보세요.

outer TX (Connection #1) — OrderService.createOrder()
inner TX (Connection #2) — AuditService.log() (REQUIRES_NEW)

5. NESTED vs REQUIRES_NEW

꼬리질문: "NESTED와 REQUIRES_NEW의 차이를 설명해주세요"

NESTED는 Savepoint를 이용해 중첩 트랜잭션을 구현합니다. inner가 실패해도 Savepoint까지만 롤백하고 outer는 계속할 수 있습니다. REQUIRES_NEW와 달리 같은 커넥션을 사용하므로 커넥션 풀 부담이 없습니다.

단, NESTED는 JPA/Hibernate 환경에서 NestedTransactionNotSupportedException이 발생할 수 있어 실무 적용에 주의가 필요합니다.

두 방식의 동작 차이를 비교해 보세요.

REQUIRES_NEW
outer TX
Connection #1
inner TX
Connection #2 (독립)
커넥션: 2개 사용
NESTED
outer TX
Connection #1
Savepoint sp1
inner (중첩)
커넥션: 1개 (Savepoint 사용)

면접 체크리스트

이 항목들을 자신 있게 설명할 수 있다면 트랜잭션 전파 질문은 준비 완료입니다.

  • - REQUIRED(기본): 기존 트랜잭션 참여 → 같이 커밋/롤백
  • - REQUIRES_NEW: 독립 트랜잭션 → outer 롤백과 무관하게 inner 커밋 가능 (커넥션 2개 주의)
  • - rollbackOnly 함정: inner 예외 catch해도 rollbackOnly 마킹은 유지됨 → UnexpectedRollbackException
  • - NESTED: Savepoint 부분 롤백 → JPA 환경 미지원 가능
  • - 실전 패턴: 감사 로그, 알림 발송 → REQUIRES_NEW로 독립 커밋 보장

참고 자료


의견을 들려주세요

서비스 개선에 큰 도움이 됩니다. 익명으로 자유롭게 남겨주세요.

0 / 1000
이전Filter vs Interceptor vs AOP (준비 중)
다음@Transactional 프록시 동작 원리 (준비 중)