목차
- 트랜잭션 전파란?
- 트랜잭션 전파 순서
- 트랜잭션 전파 속성
1. 트랜잭션의 전파란?
- 트랜잭션 전파
- 하나의 트랜잭션 내부에 다른 트랜잭션이 있는 경우, 트랜잭션 정책에 따라 어떻게 동작할 지 결정하는 것이다.
- 트랜잭션 내부에 트랜잭션이 존재하는 경우, 트랜잭션 전파 수준에 따라 트랜잭션을 새로 만들 수도 있고, rollback범위도 달라진다.
- 기본값은 REQUIRED이다.
- 트랜잭션은 데이터베이스에서 제공하는 기술이므로 커넥션 객체를 통해 처리한다. 1개의 트랜잭션을 사용한다는 것은 하나의 커넥션 객체를 사용한다는 것이다.
→ 외부 트랜잭션내에 내부 트랜잭션이 있는 경우, 둘을 묶어 하나의 트랜잭션이 됩니다.
→ 스프링에서는 로직에 있는 트랜잭션을 논리 트랜잭션이라는 단위로 생각하고, 논리 트랜잭션들을 묶은 하나의 트랜잭션을 물리 트랜잭션이라고 한다.
- 논리 트랜잭션 : 스프링이 트랜잭션 매니저를 통해 트랜잭션을 처리하는 단위
- 물리 트랜잭션 : 실제 데이터베이스에 적용되는 트랜잭션으로, 커넥션을 통해 커밋/롤백하는 단위
- 특징
- 모든 논리 트랜잭션이 커밋 되어야 물리 트랜잭션이 커밋된다.
- 하나라도 논리 트랜잭션이 롤백되면 물리 트랜잭션 내에 있는 모든 트랜잭션은 롤백된다.
- 스프링에서는 트랜잭션이 여러 개인 경우, 첫 논리 트랜잭션이 물리 트랜잭션을 시작시키며 최종 커밋한다.
- 외부 트랜잭션만이 커넥션 작업을 발생시킨다.
- 내부 트랜잭션은 새로운 트랜잭션을 만들지 않는다.
트랜잭션 전파 동작 순서
- 외부 트랜잭션 시작
- 커넥션 생성
- setAutoCommit
- true : 자동으로 프로그램이 정상으로 끝나면 commit, 에러가 발생하면 rollback
- false : 사용자가 직접 commit/rollback
- 커넥션을 트랜잭션 동기화 매니저에 보관
- 트랜잭션 생성
- 로직에서 커넥션 사용
- 내부 트랜잭션 시작
- 트랜잭션 동기화 매니저에 기존 트랜잭션이 존재하는지 확인
- 트랜잭션 동기화 매니저에 외부 트랜잭션 로직을 수행했던 커넥션이 보관되어 있다. 이 커넥션을 내부 트랜잭션에서 그대로 사용.
- 기존 트랜잭션에 참여, 새로운 트랜잭션을 생성하지 않는다.
- 로직에서 커넥션 사용
- 내부 트랜잭션(논리 트랜잭션) 커밋
- 외부 트랜잭션(논리 트랜잭션) 커밋
- DB 커넥션(물리 트랜잭션)에 커밋 호출.
→ 전파 속성은 REQUIRED를 전제로 한다.
- 외부 롤백 트랜잭션 전파 순서
내부 트랜잭션 커밋 → 외부 트랜잭션 롤백 요청 → 트랜잭션 매니저에서 DB커넥션에 롤백 호출 → 데이터베이스에 롤백 적용 후 트랜잭션 종료
- 내부 롤백 트랜잭션 전파 순서
내부 트랜잭션 롤백 → 트랜잭션 동기화 매니저 rollbackOnly = true로 표시 (DB 커넥션에 롤백을 호출X) → 외부 트랜잭션에서 커밋 요청 → rollbackOnly 설정 확인 → rollbackOnly = true 확인 후 롤백 및 예외(UnexpectedRollbackException)를 발생시킴
외부 트랜잭션의 경우 실제 커밋을 호출하기 위해 트랜잭션 동기화 매니저에서 커넥션을 흭득해야 하는데 그것을 rollbackOnly = true 막는다.
트랜잭션 전파 속성(Transaction Propagation)
1. 트랜잭션 전파 속성이란?
- 이미 트랜잭션이 진행중일 때 추가 트랜잭션 진행을 어떻게 할 지 결정하는 것이다.
2. 다양한 스프링의 트랜잭션 전파 속성
- REQUIRED
- 스프링이 제공하는 기본적인(DEFAULT) 전파 속성이다.
- 내부 트랜잭션이 기존에 존재하는 외부 트랜잭션에 참여한다.
- REQUIRES_NEW
- 외부 트랜잭션과 내부 트랜잭션을 완전히 분리하는 전파 속성
- 2개의 물리 트랜잭션이 사용된다.
- 2개의 물리 트랜잭션이 사용된다는 것은 각각의 DB 커넥션이 사용된다는 것이다.
- 각각 트랜잭션 별로 커밋과 롤백이 수행된다.
- 1개의 HTTP 요청에 대해 2개의 커넥션이 사용되는 것이다. 내부 트랜잭션이 처리 중일 때 외부 트랜잭션이 대기하는데, 이것은 데이터베이스 커넥션을 고갈시킬 수 있다. 그렇기에 REQUIRES_NEW 없이 해결가능한 문제는 최대한 대안책을 사용하는 것이 좋다.
- SUPPORTS
- 이미 시작된 트랜잭션이 있으면 참여, 그렇지 않으면 트랜잭션 없이 진행한다.
- MANDATORY
- 이미 시작된 트랜잭션이 있으면 참여하고, 없으면 새로 시작하는 대신 없으면 예외를 발생시킨다.
- 혼자서 독립적으로 트랜잭션을 진행하면 안되는 경우에 사용
- NOT_SUPPORTED
- 이미 진행중인 트랜잭션이 있으면 이를 보류시키고, 트랜잭션을 사용하지 않도록 한다.
- NEVER
- 이미 진행중인 트랜잭션이 있으면 예외를 발생시키며, 트랜잭션을 사용하지 않도록 강제한다.
- NESTED
- 이미 진행중인 트랜잭션이 있으면 중첩(자식) 트랜잭션을 시작한다.
- 트랜잭션 안에 다시 트랜잭션을 만드는 것으로, 독립적으로 트랜잭션을 만드는 REQUIRES_NEW와는 다르다.
- 중첩(자식) 트랜잭션은 부모의 커밋, 롤백의 영향을 받지만 자신의 커밋, 롤백의 영향을 주지는 않는다.
[Reference]
'DB' 카테고리의 다른 글
JOIN으로 성능 개선하기 (0) | 2025.02.16 |
---|