본문 바로가기

Programming/Java & JSP & Spring

[Spring] REQUIRES_NEW과 Exception (REQUIRES_NEW는 정말 독립적인가?)

흔히들 많이 사용하고 기본적으로 작동하는 것이 Propagation.REQUIRED 전파 레벨을 사용한다.

그 다음은 여러 이유로 REQUIRES_NEW 전파 레벨이 사용되는 편인데, 이 둘의 개념을 먼저 간단히 살펴보자.

 

Propagation.REQUIRED

트랜잭션이 존재하면 기존의 트랜잭션이 전파된다. 만약 존재하지 않는다면 트랜잭션을 새로 시작한다.

 

Propagtion.REQUIRES_NEW

매번 새로운 트랜잭션을 생성한다. 

 

그렇다면 REQUIRES_NEW는 부모 트랜잭션에서 완전 독립적인 트랜잭션을 생성하는가 ?

꽤나 많은 곳에서 REQUIRES_NEW는 부모와는 아예 독립된 공간을 생성하는 것으로 표현되고 있고 나 역시 그렇게 알고 있었다.

독립된 공간은 부모 트랜잭션과 새롭게 생긴 자식 트랜잭션이 exception으로부터 완전 독립된 것으로 이해했다.

 

하지만 실제로는 그렇지 않았다.

결론부터 말하자면 새롭게 생긴 자식 트랜잭션에서 Exception이 발생하면 부모 트랜잭션까지 전파된다.

 

예제를 살펴보자

 

1. 부모 Tx -> 자식 New Tx Exception 발생

fun propagation() {
	println("parent tx start !")
    repository.save(FruitInfo(name = "banana")) 
    
    // throw exception in requires_new tx 
    propagationService.childRequiresNewTxIncludeException()
    
    // 부모 tx -> 자식 tx (exception 발생) : 부모 + 자식 둘 다 롤백
}

 

2. 부모 Tx -> 자식 New Tx -> 부모 Tx Exception 발생 

fun propagation() {
	println("parent tx start !")
    repository.save(FruitInfo(name = "banana"))
    
    propagationService.childRequiresNewTx()
    
    throw RuntimeException()
    
    // 부모 tx -> 자식 tx -> 부모 tx (exception 발생) : 자식 tx는 커밋되고 부모만 롤백
}

 

그럼 어떤 경우에 REQUIRES_NEW 전파 레벨을 사용하는 것이 좋을까?

여러 경우가 있겠지만 몇가지만 뽑으면 다음과 같다.

- 부모 트랜잭션에서 Exception이 발생해도 커밋이 되어야 하는 경우

- 부모 트랜잭션에서 자식 트랜잭션을 try - catch 하고 싶은 경우 (일반 트랜잭션으로 하면 try - catch가 롤백 마킹때문에 의도대로 작동하지 않음)