백엔드 개발자 블로그

@Transactional 본문

Spring

@Transactional

backend-dev 2024. 5. 13. 20:36

@Transactional에 대해서 알아보자

 

@Transactional이란?

  • 스프링에서 트랜잭션 처리할 때 사용하는 어노테이션이다.
  • 클래스, 인터페이스, 메소드에 사용할 수 있다.

 

작동순서

  1. 프록시 객체 생성
  2. PlatformTransactionManager를 사용하여 트랜잭션을 시작
  3. 메소드 실행
  4. 결과에 따라 Commit 또는 Rollback

 

Commit과 Rollback 발생하는 경우

  • CheckedException or 예외가 없을 때는 Commit
  • UncheckedException이 발생하면 Rollback

 

우선순위

  1. 클래스 메소드
  2. 클래스
  3. 인터페이스 메소드
  4. 인터페이스

설정 

@Transactional 설정

속성 타입 설명
value String 사용할 트랜잭션 관리자
propagation enum: Propagation 선택적 전파 설정
isolation enum: Isolation 선택적 격리 수준
readOnly boolean 읽기/쓰기 vs 읽기 전용 트랜잭션
timeout int (초) 트랜잭션 타임 아웃
rollbackFor Throwable 로부터 얻을 수 있는 Class 객체 배열 롤백이 수행되어야 하는, 선택적인 예외 클래스의 배열
rollbackForClassName Throwable 로부터 얻을 수 있는 클래스 이름 배열 롤백이 수행되어야 하는, 선택적인 예외 클래스 이름의 배열
noRollbackFor Throwable 로부터 얻을 수 있는 Class 객체 배열 롤백이 수행되지 않아야 하는, 선택적인 예외 클래스의 배열
noRollbackForClassName Throwable 로부터 얻을 수 있는 클래스 이름 배열 롤백이 수행되지 않아야 하는, 선택적인 예외 클래스 이름의 배열

주의사항

1. 인터페이스가 없는 경우

  • @Transactional 어노테이션은 Spring AOP를 이용한다. 즉, Dynamic Proxy를 이용한다.Dynamic Proxy는 인터페이스 기반으로 동작하기 때문에 인터페이스가 없을경우 트랜잭션이 동작하지 않는다.
  • 인터페이스 없이 트랜잭션 동작하게 하려면 CGLib(Code Generation Library) Proxy를 이용하면 된다.CGLib Proxy는 클래스에 대한 Proxy가 가능하기 때문에 인터페이스가 없어도 된다.

 

2. @Transactional은 public method에만 적용된다.

  • @Transactional은 프록시 기반으로 동작하기 때문에 public method가 아니면 동작하지 않는다.
  • 만약 private 에 @Transactional을 적용한다고 하면 IDE에서 컴파일 오류가 발생한다.

img

 

3. 동일한 클래스 내의 메소드 호출은 @Transactional이 동작하지 않는다.

클래스내의 한 메소드에서 @Transactional가 적용된 다른 메소드를 호출하면 @Transactional이 동작하지 않는다. 프록시로 접근하지 않고 직접 접근하기 때문이다.

@Controller
class PackingController {
	packingService.packing();	
}

@Service
class PackingService {		
	// 트랜잭션 선언되어있지 않음.
	public void packing() {
		...
		callExternalApi();
		processCompleted();
	}

	@Transactional
	public void callExternalApi() {
		...
	}

	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void processCompleted() {
		...
	}
}

클래스 내 메소드를 호출하여 @Transactional을 동작하고 싶다면?

  • 가장 간단한 방법은 새로운 클래스를 생성하여 메소드를 위임하는 것이다.
  • 클래스 생성이 어렵다면 aspectj를 사용하면 된다.
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true, mode = AdviceMode.ASPECTJ)
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class AspectjApplication {
    public static void main(String[] args) {
        SpringApplication.run(AspectjApplication.class, args);
    }
}

참고

'Spring' 카테고리의 다른 글

Dispatcher Servlet  (0) 2024.05.17
@Controlleradvice, @ExceptionHandler  (0) 2024.05.16
OSIV  (0) 2024.05.11
DB 트래픽 분산  (0) 2024.05.11
Redisson trylock 내부로직  (0) 2024.05.11