[SpringBoot] 트랜잭션 전파 속성 (Transaction propagation)
애플리케이션을 개발할 때 데이터의 일관성을 유지하고 안정적인 동작을 보호하기 위해 트랜잭션 관리가 필수적입니다.
트랜잭션은 데이터를 처리하는 동안 발생할 수 있는 오류나 시스템 장애에 대비해 작업을 롤백(rollback)
하거나 커밋(commit)
하는 중요한 역할을 합니다. 트랜잭션 전파(Transaction Propagation)
는 여러 개의 트랜잭션이 서로 어떻게 상호작용하고, 하나의 트랜잭션이 다른 트랜잭션에게 어떻게 영향을 미칠지 결정하는 중요한 개념입니다.
이번 포스팅에서는 트랜잭션 전파에서 각 속성들의 개념과 동작과정에 대해 알아보도록 하겠습니다.
트랜잭션 전파 속성(Transaction Propagation)이란?
Spring이 제공하는 선언적 트랜잭션(@Transactional)은 여러 트랜잭션을 묶어 하나의 큰 트랜잭션 경계를 설정할 수 있는 장점이 있습니다.
여기서 트랜잭션 전파 속성(Propagation)
은 이미 트랜잭션이 진행 중일 때, 새로운 트랜잭션이 어떻게 처리될지를 결정하는 중요한 개념입니다.
전파 속성에 따라 기존의 트랜잭션에 참여하거나, 새로운 트랜잭션을 시작하거나, 에러를 발생시키는 등 다양한 행동을 선택할 수 있습니다. 이는 애플리케이션의 복잡한 비즈니스 로직을 처리하는데 유용하게 사용됩니다.
스프링 프레임워크의 org.springframework.transaction.annotation 패키지에 있는 @Transactional
어노테이션은 트랜잭션의 전파 레벨을 정할 수 있습니다.
// ex @Transactional(propagation = Propagation.REQUIRED)
물리 트랜잭션과 논리 트랜잭션

트랜잭션은 데이터베이스에서 제공하는 기술이므로 커넥션 객체를 통해 처리합니다. 한 개의 트랜잭션을 사용한다는 것은 하나의 커넥션 객체를 사용한다는 것이고, 실제 데이터베이스의 트랜잭션을 사용한다는 점에서 물리 트랜잭션이라고도 합니다. 물리 트랜잭션은 실제 커넥션에 롤백, 커밋
을 호출하여 해당 트랜잭션의 종료를 의미합니다.
동작 과정
- 물리 트랜잭션 시작 (START TRANSACTION)
- 물리 트랜잭션은 실제 데이터베이스에서 트랜잭션을 시작하는 단계입니다. 데이터베이스와 연결된 커넥션을 통해 트랜잭션이 시작됩니다.
- 로직 수행 → 물리 트랜잭션 생성 → DB (START TRANSACTION)
- 논리 트랜잭션 시작, 물리 트랜잭션 참여
- @Transactional이 적용된 로직이 호출되면 논리 트랜잭션이 시작됩니다.
- 논리 트랜잭션 → 물리 트랜잭션 참여 (이미 존재하는 물리 트랜잭션에 참여 혹은 새로운 물리 트랜잭션 생성 요청)
- 논리 트랜잭션 종료
- 논리 트랜잭션이 종료될 때, 그 안에 포함된 모든 물리 트랜잭션도 커밋하거나 롤백을 통해 종료되어야 합니다. 논리 트랜잭션이 성공적으로 커밋되면, 그에 속한 물리 트랜잭션도 커밋됩니다.
- 물리 트랜잭션 커밋
- 모든 논리 트랜잭션이 종료되면, 물리 트랜잭션은 DB에 실제 변경을 반영하기 위해 커밋됩니다. 이때, 물리 트랜잭션의 상태가 DB에 반영되고 트랜잭션이 종료됩니다. (하나의 논리 트랜잭션이라도 실패 시 롤백)
- 물리 트랜잭션 → DB (COMMIT)
- 하나의 트랜잭션 종료
- 논리 트랜잭션과 그에 속한 모든 물리 트랜잭션이 커밋되면 전체 트랜잭션이 종료됩니다.
논리 트랜잭션
은 스프링이 관리하지만, 물리 트랜잭션
은 실제 데이터베이스와 연결되어 커밋, 롤백을 처리합니다.
- 물리 트랜잭션: 실제 데이터베이스에 적용되는 트랜잭션으로, 커넥션을 통해
커밋, 롤백
하는 단위 - 논리 트랜잭션: 스프링이 트랜잭션 매니저를 통해 트랜잭션을 처리하는 단위
- 모든
논리 트랜잭션이 커밋 되어야 트랜잭션이 커밋
됩니다. 하나의 논리 트랜잭션이라도 롤백되면 물리 트랜잭션 또한 롤백
됩니다.
- 모든
트랜잭션 전파 속성 옵션
// ex @Transactional(propagation = Propagation.REQUIRED)
트랜잭션 전파 설정은 @Transactional
의 옵션 propagation
을 통해 설정이 가능합니다.
- REQUIRED
- REQUIRES_NEW
- NESTED
- MANDATORY
- SUPPORTS
- NOT_SUPPORTED
- NEVER
트랜잭션의 전파 레벨에는 위와 같이 7가지가 존재합니다. 각 전파 레벨에 대해 알아보도록 하겠습니다.
REQUIRED : default

REQUIRED는 스프링이 제공하는 기본(default) 전파 속성으로, 기본적으로 2개의 논리 트랜잭션을 묶어 1개의 물리 트랜잭션을 사용하는 것입니다.
REQUIRED 동작 과정
- 로직 수행 시작
- 애플리케이션에서 로직1을 호출합니다.
- 물리 트랜잭션 생성
- @Transactional(propagation = REQUIRED)가 적용된 로직2를 호출합니다.
로직1
의 논리 트랜잭션 참여- 로직1은 생성된 물리 트랜잭션에 참여합니다.
로직1 → 로직2 호출
- 로직1 내부에서 @Transactional(propagation = REQUIRED)가 적용된 로직2를 호출합니다.
로직2
의 논리 트랜잭션 참여로직2는 새로운 논리 트랜잭션으로 간주
되지만,로직1과 동일한 물리 트랜잭션
에 참여합니다.
로직2
논리 트랜잭션 종료- 로직2의 작업이 완료되면 논리 트랜잭션이 종료되며, 물리 트랜잭션은 그대로 유지됩니다.
로직1
논리 트랜잭션 종료- 로직1의 작업까지 완료되면 모든 논리 트랜잭션이 종료됩니다.
- 물리 트랜잭션 커밋
- 모든 논리 트랜잭션이 정상적으로 커밋예약상태일 시 커밋됩니다. 여기서 단 하나의 논리 트랜잭션이라도 실패 시 롤백됩니다.
- 물리 트랜잭션 → DB (COMMIT)
REQUIRES_NEW

REQUIRES_NEW는 외부 트랜잭션과 내부 트랜잭션을 완전히 분리하는 전파 속성입니다. 2개의 물리 트랜잭션이 사용되며, 각각 트랜잭션 별로 커밋과 롤백이 수행됩니다.
REQUIRES_NEW 동작 과정
- 로직 수행 시작
- 애플리케이션에서 로직1을 호출합니다.
로직1
의 물리 트랜잭션 시작, 논리 트랜잭션 참여- 로직1의 물리 트랜잭션이 시작되고, 로직1의 논리 트랜잭션이 해당 트랜잭션에 참여합니다.
로직1 → 로직2 호출
- 로직2 호출 시 REQUIRES_NEW 전파 속성으로 인해 새로운 물리 트랜잭션이 생성되고 로직2의 논리 트랜잭션은 새로운 물리 트랜잭션에 참여합니다.
로직2
문제 발생- 로직2의 논리 트랜잭션이 종료되고 그에 해당하는 물리 트랜잭션이
롤백
됩니다. 이때, 로직2의 물리 트랜잭션은 독립적으로 처리되어로직1
의 트랜잭션에 영향을 주지 않습니다.
- 로직2의 논리 트랜잭션이 종료되고 그에 해당하는 물리 트랜잭션이
로직1
종료- 로직1의 논리 트랜잭션이 종료되고 그에 해당하는 물리 트랜잭션이 커밋됩니다.
이 속성은 로직1
과 로직2
의 트랜잭션이 독립적으로 처리되도록 보장합니다.
즉, 로직2
가 실패하더라도 로직1
의 트랜잭션은 영향을 받지않아 로직2
의 실패로 인한 로직1
의 롤백은 진행되지 않습니다.
NESTED

NESTED 동작 과정
- 부모 트랜잭션 존재 시 중첩 트랜잭션 생성
- 부모 트랜잭션 존재 시, 새로운 중첩 트랜잭션을 생성합니다. 이 트랜잭션은 부모 트랜잭션의 일부로 취급되고 부모의 커밋, 롤백에 의존합니다.
- 만약 부모 트랜잭션이 없다면, 새로운 독립적인 트랜잭션을 시작합니다. 이때 부모 트랜잭션과 별개의 트랜잭션이 처리됩니다.
- 중첩 트랜잭션 종료 시 커밋
- 중첩 트랜잭션 완료 시, 커밋은 부모 트랜잭션의 끝에서 이루어집니다. 즉, 자식 트랜잭션이 종료되더라도 부모 트랜잭션이 커밋될 때까지 실제로 데이터베이스에 반영되지 않습니다.
- 중첩 트랜잭션 롤백 발생
- 중첩 트랜잭션 롤백 시, 부모 트랜잭션에는 영향을 주지 않습니다. 즉, 중첩 트랜잭션의 실패로 인해 부모 트랜잭션이 롤백되지는 않습니다. (중첩 트랜잭션 시작 전 시점으로 롤백, 부모 트랜잭션은 정상 작동)
- 부모 트랜잭션 롤백 발생
- 부모 트랜잭션 롤백 시, 모든 트랜잭션이 롤백됩니다.
MANDATORY

반드시 부모 트랜잭션 하에서만 수행이 가능합니다. 만약, 부모 트랜잭션이 존재하지 않으면 IllegalTransactionStateException
예외를 발생시킵니다.
SUPPORTS
- 부모 트랜잭션 존재 시 트랜잭션에 참여합니다.
- 부모 트랜잭션이 존재하지 않으면 트랜잭션 없이 수행됩니다.
NOT_SUPPORTED
- 부모 트랜잭션 존재 시 트랜잭션을 보류시키고 트랜잭션 없이 수행됩니다.
- 부모 트랜잭션이 존재하지 않으면 정상적으로 트랜잭션 없이 수행됩니다.
NEVER
- 어떠한 경우에도 트랜잭션을 생성하지 않습니다.
- 부모 트랜잭션 존재 시
IlegalTransactionalStateException
예외를 발생시킵니다.
마무리
트랜잭션 전파는 애플리케이션의 안정성과 일관성을 보장합니다. 특히, 분산 시스템이나 복잡한 비즈니스 로직을 처리할 때, 적절한 전파 속성을 선택하는 것이 중요합니다.
트랜잭션 전파 속성 | 설명 |
REQUIRED | 부모 트랜잭션이 있으면 참여, 없으면 새로운 트랜잭션 생성 |
REQUIRES_NEW | 부모 트랜잭션과 상관없이 항상 새로운 트랜잭션 생성 |
NESTED | 부모 트랜잭션이 있으면 중첩 트랜잭션 생성, 없으면 새로운 트랜잭션 생성 |
MANDATORY | 부모 트랜잭션이 있으면 참여, 없으면 예외 발생 |
SUPPORTS | 부모 트랜잭션이 있으면 참여, 없으면 트랜잭션 없이 실행 |
NOT_SUPPORTED | 부모 트랜잭션이 있어도 트랜잭션 없이 실행 |
NEVER | 트랜잭션을 생성하지 않으며, 부모 트랜잭션이 있으면 예외 발생 |
'Spring' 카테고리의 다른 글
[SpringBoot] Spring Docs + Swagger 적용하여 API 문서 자동화하기 (0) | 2025.02.20 |
---|---|
[SpringBoot] Scale-out 환경에서 발생하는 Scheduler 중복 실행 문제 Shedlock으로 해결하기 (0) | 2025.02.06 |
[SpringBoot] AWS S3 다중 이미지 파일 업로드 및 삭제 구현하기 (feat. MultipartFile) (2) | 2025.01.17 |
[SpringBoot] @Scheduled를 이용한 스케줄러 구현 (0) | 2025.01.13 |
[SpringBoot] AWS SES로 이메일 전송 기능 구현하기 (0) | 2025.01.12 |
댓글을 사용할 수 없습니다.