728x90
반응형
728x90
스프링 트랜잭션 전파 Propagation
- 트랜잭션 전파는 한 트랜잭션이 다른 트랜잭션에 어떻게 영향을 미치는지를 정의
- 트랜잭션을 각각 사용하는 것이 아닌 트랜잭션이 이미 진행 중일 때 추가로 트랜잭션을 수행하는 경우
사용법
- @Transactional 어노테이션 속성 값으로 정의 하여 사용
- ex) @Transactional(propagation = Propagation.REQUIRED)
기본 옵션 Required
- 스프링 트랜잭션의 기본 설정 옵션으로 생성된 트랜잭션이 없다면 생성하고 이미 존재한다면 참여
- 처음 시작된 트랜잭션 1(외부)이 진행 중이고 트랜잭션 2(내부)가 시작되는 경우 스프링은 트랜잭션 1,2를 묶어 하나의 트랜잭션으로 만듦
- 하나로 묶인 트랜잭션은 물리 트랜잭션이 되고 내부의 트랜잭션 1,2는 논리 트랜잭션이 됨
- 물리 트랜잭션: 실제 데이터베이스에 적용되는 트랜잭션
- 논리 트랜잭션: 애플리케이션 또는 비즈니스 로직의 관점에서 정의된 트랜잭션
커밋 요청 흐름
- 트랜잭션 매니저는 getTransaction()을 호출해 트랜잭션 1(외부)을 시작
- 트랜잭션 매니저는 데이터소스를 통해 커넥션 생성
- 생성한 커넥션을 수동 커밋으로 설정 - 물리 트랜잭션 시작 단계
- 트랜잭션 매니저는 트랜잭션 동기화 매니저에 커넥션을 보관
- 트랜잭션 매니저는 트랜잭션을 생성한 결과를 TransactionStatus에 담아서 반환(신규 트랜잭션)
- 로직 1에 사용되고 커넥션이 필요한 경우 트랜잭션 동기화 매니저를 통해 트랜잭션이 적용된 커넥션 획득
- 트랜잭션 매니저는 getTransaction()을 호출해 트랜잭션 2(내부)를 시작
- 트랜잭션 매니저는 트랜잭션 동기화 매니저를 통해 기존 트랜잭션이 존재하는지 확인
- 기존 트랜잭션이 존재하므로 기존 트랜잭션에 참여
- 트랜잭션 매니저는 트랜잭션을 생성한 결과를 TransactionStatus에 담아 반환(신규 트랜잭션이 아님)
- 로직 2에 사용되고 커넥션이 필요한 경우 트랜잭션 동기화 매니저를 통해 외부 트랜잭션이 보관한 커넥션을 획득
- 로직 2가 끝나고 트랜잭션 매니저를 통해 내부 트랜잭션을 커밋
- 트랜잭션 매니저는 트랜잭션의 신규 여부에 따라 다르게 동작
- 신규 트랜잭션: 실제 데이터베이스 커밋 호출
- 신규 트랜잭션 x(생성된 트랜잭션에 참여 중인 상태): 커밋이나 롤백을 호출하지 않음
- 로직 1이 끝나고 트랜잭션 매니저를 통해 외부 트랜잭션 커밋
- 외부 트랜잭션(트랜잭션 1)은 신규 트랜잭션으로 실제 커밋을 호출
원칙
- 모든 논리 트랜잭션이 커밋되어야 물리 트랜잭션이 커밋
- 하나의 논리 트랜잭션이라도 롤백이 되면 물리 트랜잭션은 롤백
롤백 요청 흐름
- 외부 트랜잭션 롤백
- 커밋의 1~11번 과정 동일
- 로직 2가 끝나고 트랜잭션 매니저를 통해 내부 트랜잭션을 커밋
- 내부 트랜잭션은 신규 트랜잭션이 아니므로 실제 커밋 x
- 로직 1이 끝나고 트랜잭션 매니저를 통해 외부 트랜잭션 롤백
- 외부 트랜잭션의 경우 신규 트랜잭션으로 데이터베이스에 실제 롤백 호출
- 실제 물리 롤백이 호출되고 트랜잭션 1,2 모두 롤백된 상태로 트랜잭션이 끝남
- 내부 트랜잭션 롤백
- 커밋의 1~11번 과정 동일
- 로직 2가 끝나고 트랜잭션 매니저를 통해 내부 트랜잭션을 롤백(로직 2에 문제 발생으로 인한 롤백이 되는 경우)
- 내부 트랜잭션은 신규 트랜잭션이 아니므로 실제 롤백을 호출하는 대신 트랜잭션 동기화 매니저에 rollbackOnly 속성을 true로 변경 -> 해당 트랜잭션은 롤백만 가능
- 로직 1이 끝나고 트랜잭션 매니저를 통해 외부 트랜잭션을 커밋
- 외부 트랜잭션은 신규 트랜잭션으로 실제 커밋을 호출
- 그러나 내부 트랜잭션에서 변경한 rollbackOnly의 속성이 true로 롤백이 호출되어야 함
- 스프링에서 UnexpectedRollbackException 런타임 예외 발생
REQUIRES_NEW
- 항상 새로운 트랜잭션을 시작
- 기존 트랜잭션이 존재한다면 잠시 멈춰두고 새로운 트랜잭션을 시작
- 외부 트랜잭션과 내부 트랜잭션을 분리해서 각각의 별도의 물리 트랜잭션을 사용하는 방법
- 각각의 물리 트랜잭션으로 동작하기 때문에 영향을 주지 않음
- 물리 트랜잭션이 명확하게 분리되는 만큼 데이터베이스 커넥션이 동시에 추가로 사용됨
주의 사항
- 논리 트랜잭션에서 예외 발생 시 처리하여 정상 흐름으로 반환한 경우의 처리
- 예외를 처리하여 로직의 흐름을 정상으로 처리하였지만 예외가 발생한 순간 트랜잭션 매니저에는 rollbackOnly가 true로 체크되고 그다음 로직이 흐름이 처리됨
- rollbackOnly가 ture로 설정된 이상 로직이 정상 흐름으로 처리된 것과 관계 없이 무조건 물리 롤백 발생 및 UnexpectedRollbackException 발생
추가 옵션
- SUPPORT: 트랜잭션을 지원
- 기존 트랜잭션이 있음: 기존 트랜잭션 참여
- 기존 트랜잭션이 없음: 트랜잭션 없이 진행
- NOT_SUPPORT: 트랜잭션을 지원하지 않음
- 기존 트랜잭션이 있음: 트랜잭션 없이 진행
- 기존 트랜잭션이 없음: 트랜잭션 없이 진행(기존 트랜잭션은 보류)
- MANDATORY: 트랜잭션이 반드시 존재해야 함
- 기존 트랜잭션이 있음: 기존 트랜잭션 참여
- 기존 트랜잭션이 없음: IllegalTransactionStateException 예외 발생
- NEVER: 트랜잭션을 사용하지 않음
- 기존 트랜잭션이 있음: IllegalTransactionStateException 예외 발생
- 기존 트랜잭션이 없음: 트랜잭션 없이 진행
- NESTED: 중첩 트랜잭션 생성
- 기존 트랜잭션 있음: 중첩 트랜잭션을 만듬
- 중첩 트랜잭션은 외부 트랜잭션의 영향을 받지만 외부에 영향을 주지는 않음
- 중첩 트랜잭션은 롤백되어도 외부 트랜잭션 커밋 가능
- 외부 트랜잭션이 롤백되면 중첩 트랜잭션도 함께 롤백
- 기존 트랜잭션 있음: 중첩 트랜잭션을 만듬
스프링 DB 2편 - 데이터 접근 활용 기술 강의 | 김영한 - 인프런 (inflearn.com) 강의 내용 참고
728x90
'백엔드 > Spring' 카테고리의 다른 글
[Spring] JPA 개요 (1) | 2024.09.07 |
---|---|
[Spring] 변경 감지 & 병합 (0) | 2024.09.06 |
[Spring] 스프링 트랜잭션 (0) | 2024.09.04 |
[Spring] MyBatis (1) | 2024.09.01 |
[Spring] JDBC Template (3) | 2024.08.31 |