메이쁘

[Spring] 예상 Q&A 공부(Transactional 트랜잭션 적용 범위) 본문

면접 대비 CS지식/SELF CS면접 Q&A

[Spring] 예상 Q&A 공부(Transactional 트랜잭션 적용 범위)

메이쁘 2021. 12. 26. 23:13

안녕하세요.

 

CS관련 질문과 면접에 맞는 답변을 작성하면서 지식도 쌓고 면접도 대비하는 시간을 가지려고 합니다.

 

 

틈틈히 게시글을 작성하며 면접 대비 데이터셋을 확보해둔 다음

 

언젠간 면접하게 될 때 모아서 쓰려고 합니다.

 

(실제로 면접에서 들었던 질문이 아니라, 제가 스스로 답을 정해놓고 짜논 질문이라 이렇게 안나올 수 있습니다!!!)

 

 

 

이번 글은 Spring 카테고리 입니다.

 

 

 

 

  -- 질문 목록

 

Q1.  상위 메소드에서 @Transactional 어노테이션을 적용하지 않고, 하위 메소드에서만 적용했을 때, 상위 메소드에서 하위 메소드 호출 시 Transaction이 반영되지 않는 이유는?

Q2.  그럼, 상위 메소드 및 하위 메소드 둘 다 @Transactional 어노테이션을 적용했을 때, 트랜잭션이 어떻게 동작할까요?

Q3. @Transactional 어노테이션을 추가해도 트랜잭션이 적용되지 않는 경우는 무엇이 있을까요?


Q1.  상위 메소드에서 @Transactional 어노테이션을 적용하지 않고, 하위 메소드에서만 적용했을 때, 상위 메소드에서 하위 메소드 호출 시 Transaction이 반영되지 않는 이유는?

 

A. 트랜잭션은 Proxy 기반으로 동작하며, AOP로 구성되어 있기 때문에 트랜잭션 어노테이션이 있는 다른 내부 메소드를 호출해도 트랜잭션이 동작하지 않습니다. 이는 곧 메소드가 실행되기 전/후로 자동으로 트랜잭션을 묶습니다. 즉, Spring에서는 빈 인스턴스(인터페이스 기반)에서 처음 호출하는 메소드나 클래스의 속성을 따라가기 때문에 상위 메소드에 @Transactional 어노테이션이 존재하지 않으면 존재하지 않은 채로 어떤 로직을 수행하던지 간에 메소드 종료 시 까지 트랜잭션이 적용되지 않게 됩니다. 

 

 

 

 

Q2. 그럼, 상위 메소드 및 하위 메소드 둘 다 @Transactional 어노테이션을 적용했을 때, 트랜잭션이 어떻게 동작할까요?

 

A. 위와 마찬가지로, 상위 메소드만 트랜잭션이 적용되고, 하위 메소드의 트랜잭션은 무시됩니다. 하위 메소드에 @Transactional 어노테이션이 존재하더라도 새로운 트랜잭션이 생성되는 것이 아니라 상위 메소드의 트랜잭션에 참여하게 됩니다. 이는 @Transactional 어노테이션의 propagation(전파 레벨)의 default 속성이 REQUIRED인데, 이것은 기존 트랜잭션이 존재하는 경우는 해당 트랜잭션에 참여하고, 존재하지 않을 땐 새로운 트랜잭션을 생성해서 진행하는 속성입니다. 그렇기 때문에, 하위 메소드에서 전파 레벨을 변경하지 않는 한 상위 메소드의 트랜잭션에 따라가게 됩니다.

*** 대신, Q3의 답변처럼 Self Injection을 통한 내부 메소드 호출 시의 얘기이고, Self Injection이 아닌 경우 AOP 특성 상 내부 메소드는 트랜잭션이 적용되지 않습니다.

 

 

 

 

Q3. @Transactional 어노테이션을 추가해도 트랜잭션이 적용되지 않는 경우는 무엇이 있을까요?

 

A. 우선, 첫 번째로 public 함수가 아닌 private 함수에 적용한 경우가 있습니다. 메소드가 public 접근일 경우에만 트랜잭션이 적용됩니다.

다음으로, 상위 함수에 @Transactional 어노테이션이 추가되어 있지 않은 경우, @Transactional 어노테이션이 추가된 하위 함수를 호출해도 트랜잭션이 실행되지 않습니다.

이를 해결하기 위해서는 상위 함수에 어노테이션을 추가하거나, 인터페이스 기반의 새로운 Bean instance를 만들어 활용하는 Bean 및 Class 분리 방법Self Injection을 통해 자기 자신의 빈 인스턴스를 활용하는 방법이 있습니다. 

(잘 모르지만) 또, 별도의 Transaction Handler class를 만들어 사용하는 방법도 있습니다.

class TransactionHandler {
  @Transactional
  public <T> T execute(Supplier<T> supplier) {
    return supplier.get();
  }
}

public void transaction() {
  transactionHandler.execute(() -> this.foo());
}

 

 

이상입니다.

 

감사합니다.

Comments