본문 바로가기

CS

트랜잭션 전파 제어

기본 개념

 

롤백 온리 (Rollback-Only): 장바구니에 물건을 담고 "결제하기 전"에 비우는 것처럼, 물리적으로 데이터베이스까지 변경 사항이 전송되지 않으므로 실제 데이터베이스에 아무런 영향을 미치지 않는 상태를 말합니다.

 

Spring과 Hibernate 환경에서는 트랜잭션 도중 문제가 발생하거나 명시적으로 롤백 온리 상태로 설정되면, 해당 트랜잭션이 더 이상 커밋될 수 없음을 나타냅니다.

 

물리 롤백 (Physical Rollback): 이미 결제가 완료된 후 환불을 진행하는 것처럼, 데이터베이스에 반영된 변경 사항을 다시 되돌리는 과정을 의미합니다.

 

Spring과 Hibernate 환경에서는 실제 데이터베이스에 변경 사항이 반영되었는지 여부와 상관없이, 트랜잭션을 종료하고 데이터베이스 연결을 해제하는 과정을 의미합니다. 즉, 데이터베이스 변경 사항이 반영되지 않았더라도, 트랜잭션 자체가 롤백 상태로 종료되는 상황을 포함합니다.


트랜잭션 전파 속성

 

개발을 하면서 트랜잭션을 많이 사용하게 되는 데 해당 트랜잭션을 사용하게 되면 단독으로 트랜잭션을 설정한 메서드를 컨트롤러와 연결하여서 사용하기도 하겠지만

 

좀 더 로직이 복잡해지다보면 트랜잭션이 붙은 메서드들을 조합하여 컨트롤러에 연결하곤 합니다. 이럴 때에 개발자가 뜻하지 않게 트랜잭션은 물리 트랜잭션과 내부 논리 트랜잭션을 형성하는데 아직 이해가 되진 않아도 후에 자세히 서술하겠습니다.

 

 

먼저 개발 시 많이 사용되는 @Transactional 어노테이션 안을 살펴보겠습니다.

public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    String[] label() default {};

    Propagation propagation() default Propagation.REQUIRED; <- ** 이것만 보면 됩니다 **

 

 

코드를 보시면 트랜잭셔널 어노테이션은 프로퍼게이션 속성을 사용하며 기본 값으로 Required 타입을 사용합니다. 다른 타입들을 보자면 아래와 같은데요

 

 

여기서 중요한 것은 Required 와 Requires_new 타입입니다. 나머지는 이에 연관되어서 추가적인 동작을 하는 타입이므로 이 두 가지만을 중점적으로 보시면 됩니다.

 

REQUIRED
기존에 트랜잭션이 있는 상황 기존 물리 트랜잭션에 논리 트랜잭션으로 참여한다
기존에 트랜잭션이 없는 상황 물리 트랜잭션을 생성한다

REQUIRES_NEW
기존에 물리 트랜잭션이 있는 것과 상관없이 항상 새로운 물리 트랜잭션을 생성한다

스프링에서의 트랜잭션 조합 원리

 

https://www.youtube.com/watch?v=b0s9RzKyHN0

 

기존의 트랜잭션이 진행 중일 때 새로운 트랜잭션이 시작되면 분류하기 위해 외부 트랜잭션과 내부 트랜잭션으로 구분하며 구분하는 기준은 호출을 하는 쪽으로 외부 트랜잭션이 상대적으로 바깥에 있기 때문입니다

 

그리고 스프링에서는 이 둘을 하나의 트랜잭션으로 묶어주며 이걸 내부 트랜잭션이 외부 트랜잭션에 참여한다 라고 표현합니다

https://www.youtube.com/watch?v=b0s9RzKyHN0

 

 

스프링은 이해를 돕기 위해 논리 트랜잭션과 물리 트랜잭션 이라는 개념을 사용하는데 여러 논리 트랜잭션을 하나의 물리 트랜잭션으로 묶는다라고 이해하면 된다

 

물리 트랜잭션이란 실제 데이터베이스에 적용되는 트랜잭션이다 실제 커넥션을 통해서 시작하고 커밋과 롤백을 하는 단위이다 논리 트랜잭션도 커밋과 롤백을 요청할 수 있지만 실제 데이터베이스에 적용되진 않습니다

 

만약 저러한 형식으로 물리 트랜잭션이 되어 있고 내부적으로 논리 트랜잭션이 형성이 되어있는 경우. 논리 트랜잭션 중 하나라도 롤백온리가 된다면 전체를 아우르는 물리 트랜잭션은 물리 롤백이 됩니다

 

즉 모든 논리 트랜잭션이 모두 커밋돼야 물리 트랜잭션이 커밋이 됩니다.  여기서 중요한 점은 최초로 물리 트랜잭션을 만든 신규 트랜잭션만이 물리 트랜잭션을 종료 할 수 있습니다.

 


상황을 통한 이해

 

 

https://www.youtube.com/watch?v=b0s9RzKyHN0

 

 

 

영화를 예매한다는 상황을 가정해보면 영화 예매를 위한 트랜잭션과 이를 기록하는 로그 저장 트랜잭션으로 나누어진다고 해보겠습니다. 그리고 영화 예매와 로그 저장은 하나의 트랜잭션으로 이루어져야 되기 때문에 영화 서비스 트랜잭션이 있습니다.

 


트랜잭션이 성공하였을 때

 

https://www.youtube.com/watch?v=b0s9RzKyHN0

 

1. 영화 서비스 트랜잭션은 기존에 트랜잭션이 없으니 자신이 새로운 물리 트랜잭션을 만듭니다. 

 

2. 이후 영화 예매 트랜잭션기존에 이미 물리 트랜잭션이 있으므로 참여하게 됩니다

 

3. 마지막 로그 저장 트랜잭션은 기존에 이미 물리 트랜잭션이 있으므로 참여하게 됩니다.

 

4. 롤백 되는 것 없이 논리 트랜잭션 모두 성공적으로 커밋되어 물리 트랜잭션이 최종적으로 커밋이 됩니다.

 

 


트랜잭션이 실패하였을 때

 

https://www.youtube.com/watch?v=b0s9RzKyHN0

 

 

해당 상황에서는 이전 상황과 마찬가지로 트랜잭션을 생성하고 잇따라 트랜잭션들이 참여하여 물리 트랜잭션과 논리 트랜잭션 상황이 구축이 되었지만

 

만일 로그 저장 트랜잭션이 롤백온리가 되게 된다면 모든 것을 아우르는 물리 트랜잭션 자체가 물리 롤백이 되어버려 모든 거래는 끝이나 버리게 됩니다.

 

사실 하나라도 실패하면 끝내는 게 맞는 경우도 있기에 나쁜 상황은 아니지만, 해당 경우를 생각해보면 만일 사용자가 영화를 예매하려고 하였지만 예매 트랜잭션은 성공하였어도 사용자와 아무 관련이 없는 로그 트랜잭션이 실패되었다는 이유로 사용자가 영화 예매를 못하게 된다면 사용자는 서비스를 이탈하게 될 것입니다.

 


전파 속성 변경으로 해결

 

 

https://www.youtube.com/watch?v=b0s9RzKyHN0

 

로그 저장 트랜잭션이 서비스 예매를 하는 트랜잭션의 성공에 관여를 하면 안 되는 상황이기에 기본 전파 속성 값인 required 에서 requires_new라는 타입을 지정 하면 물리 트랜잭션이 완전히 분리가 됩니다 분리가 되면 각각의 커밋과 롤백은 서로에게 영향을 미치지 않습니다.

 

 

https://www.youtube.com/watch?v=b0s9RzKyHN0

 

 

로그를 보게 되면 영화 서비스 트랜잭션영화 예매 트랜잭션은 하나의 물리 트랜잭션 단위를 갖게 되고 로그 저장 트랜잭션은 분리되어 자신이 새로운 물리 트랜잭션이 됩니다.

 

그래서 각각의 물리 트랜잭션은 연관이 되어 있어도 물리 트랜잭션이 서로 독립적으로 동작하기 때문에, 하나의 물리 트랜잭션이 롤백되더라도 다른 물리 트랜잭션은 영향을 받지 않고 성공적으로 커밋할 수 있게 됩니다.

 

즉 비즈니스 로직 상에서는 논리적인 연관성을 가질 수 있어도 트랜잭션 레벨에서는 서로 완전히 분리되어 있는 상황인 것입니다.


마무리

 

 

논리 트랜잭션이 하나라도 롤백되면 관련된 물리 트랜잭션은 롤백되기에 이를 해결하기 위해서 requires_new 전파 타입을 사용해서 트랜잭션을 분리해야 합니다.

 

하지만 주의할 점이 있는데 requires_new를 사용한 만큼 트랜잭션 수도 늘어납니다 그래서 하나의 웹 요청에 트랜잭션의 수만큼 DB 커넥션 생성되기 때문에 만약에 성능이 중요한 상황에서라면 조심해서 사용할 필요가 있습니다.

'CS' 카테고리의 다른 글

Spring Data JPA에서 새로운 Entity인지 판단하는 방법은 무엇일까요?  (0) 2025.04.08
스프링 Ioc와 DIP란?  (1) 2025.02.10
Thread Pool이란?  (1) 2025.01.20
HTTPS란?  (0) 2025.01.13
[JPA] 다양한 연관관계 매핑  (1) 2024.12.25