반응형
트랜잭션이 진행 중인 상황에서 추가로 트랜잭션을 수행하는 경우에 어떻게 동작해야 하는지 결정하는 것을 트랜잭션 전파라고 한다. 스프링에서의 트랜잭션 전파 과정에 대해 알아보자.
물리 트랜잭션과 논리 트랜잭션
- 트랜잭션을 각각 사용하는 것이 아니라, 트랜잭션이 이미 진행 중인데 여기에 추가로 트랜잭션을 수행한다면 어떻게 될까?
- 이 경우에 어떻게 동작해야 하는지 결정하는 것을 트랜잭션 전파(propagation)라고 한다.
- 스프링은 이해를 위해 물리 트랜잭션과 논리 트랜잭션이라는 개념을 나누었다.
- 물리 트랜잭션: 실제 DB에 적용되는 트랜잭션. 실제 커넥션을 통해 트랜잭션을 시작하고 커밋/롤백하는 단위이다.
- 논리 트랜잭션: 트랜잭션 매니저를 통해 트랜잭션을 사용하는 단위이다.
원칙
- 모든 논리 트랜잭션이 커밋되어야 물리 트랜잭션이 커밋된다.
- 하나의 논리 트랜잭션이라도 롤백되면 물리 트랜잭션은 롤백된다.
트랜잭션 전파 과정
1. 정상 동작하는 경우 - 외부 및 내부 모두 커밋
- 외부 트랜잭션이 시작하면 트랜잭션 매니저는 트랜잭션 동기화 매니저를 확인하여 기존에 트랜잭션이 없음을 확인하고 물리 트랜잭션을 시작 및 동기화 매니저에 보관한다.
- 내부 트랜잭션이 시작하면 트랜잭션 매니저는 트랜잭션 동기화 매니저를 확인하여 기존 트랜잭션이 있음을 확인하고 기존 트랜잭션에 참여한다. (아무것도 하지 않는다)
- 트랜잭션 매니저는 커밋 시점에 트랜잭션이 신규인지 여부에 따라 다르게 동작한다. 내부 트랜잭션은 신규가 아니기 때문에 실제 커밋을 호출하지 않는다.
- 내부 트랜잭션에서 실제 커밋을 호출한다면 트랜잭션이 끝나 커넥션이 종료되기 때문에 외부 트랜잭션이 커밋이나 롤백을 수행할 수 없게 된다.
- 외부 트랜잭션 커밋 시점에는 신규 트랜잭션이기 때문에 실제 커밋을 호출하고 트랜잭션이 종료된다.
❕ 트랜잭션 매니저에 커밋을 호출해도 항상 실제 물리 커밋이 발생하지는 않는다.
2. 외부 트랜잭션이 롤백되는 경우
- 외부 트랜잭션 코드에서 롤백을 요청하면 트랜잭션 매니저는 신규 트랜잭션임을 확인하고 실제 물리 롤백을 호출한다.
3. 내부 트랜잭션이 롤백되는 경우
- 내부 트랜잭션이 코드에서 롤백을 요청하면 트랜잭션 매니저는 신규 트랜잭션인지 확인한다. 신규 트랜잭션이 아니기 때문에 실제 롤백을 호출하지 않는다. 다만 기존 트랜잭션에 롤백 전용 표시(rollbackOnly=true)를 한다.
- 외부 트랜잭션 커밋 시점에 트랜잭션 매니저는 rollbackOnly 설정을 확인한다. 롤백 전용 표시가 되어있다면 실제 물리 롤백을 호출한다.
- UnexpectedRollbackException
- 커밋을 호출했지만 롤백 전용 표시로 인해 실제로는 롤백이 일어났으므로, 기대하지 않은 롤백이 일어났다는 런타임 예외를 던진다.
트랜잭션 전파 옵션
REQUIRED
- 기본 설정값이다. 실무에서 대부분 사용하는 옵션이다.
- 트랜잭션이 필수(required)라는 의미이다. 기존 트랜잭션이 없으면 생성하고, 있으면 참여한다.
REQUIRES_NEW
- 항상 새로운 트랜잭션을 생성한다.
- 트랜잭션 시작 시에 REQUIRES_NEW 옵션으로 설정되어 있다면 항상 새로운 트랜잭션을 생성한다. 만약 기존 트랜잭션이 있다면 해당 트랜잭션은 잠시 보류해두고, 현재 트랜잭션이 끝날 때까지 현재 트랜잭션만 사용한다. 트랜잭션이 끝나면 보류해두었던 기존 트랜잭션을 다시 사용한다.
- 물리 트랜잭션을 분리하여 사용할 수 있지만 DB 커넥션이 한 요청(스레드)에서 동시에 2개가 사용되므로 주의해야 한다.
- 사용량이 몰리는 서비스에서는 실사용자는 500명인데 커넥션은 1000개가 사용되어서 커넥션이 모자라 사용자를 더 못받는 문제가 생길 수 있다.
- 간단한 구조 변경으로 문제를 해결할 수 있는 경우는 그렇게 하고, 구조가 너무 복잡해지는 경우에만 위 문제점을 주의해서 REQUIRES_NEW 옵션을 사용하도록 하자.
기타
- SUPPORT: 트랜잭션이 있으면 참여, 없으면 없이 진행
- NOT_SUPPORT: 항상 트랜잭션 없이 진행 (기존꺼는 보류)
- MANDATORY: 트랜잭션이 있으면 참여, 없으면 IllegalTransactionStateException 예외 발생
- NEVER: 트랜잭션이 없으면 없이 진행, 있으면 IllegalTransactionStateException 예외 발생
- NESTED: 트랜잭션이 있으면 참여, 없으면 중첩 트랜잭션 생성(외부 트랜잭션에 영향을 받지만 영향을 주지 않음). JPA에서는 사용 불가
728x90
반응형
'Java' 카테고리의 다른 글
@Transactional과 스프링 트랜잭션 AOP (0) | 2024.02.20 |
---|---|
[JAVA/JUnit5/Mokito] given() - 메소드 파라미터가 특정 클래스이면서 특정 필드 값을 가지는 경우 분기하기 (0) | 2021.11.27 |
리눅스 계열 OS에서 MariaDB(MySQL) 설치 및 이클립스 연동 방법 (0) | 2021.09.07 |
댓글