스프링에서 제공하는 트랜잭션 처리 중 하나이다. 어노테이션으로 트랜잭션 처리를 지원한다. 선언적 트랜잭션 이라고도 부른다. 클래스나 메소드에 붙여줄 경우, 해당 범위 내 메소드가 트랜잭션이 되도록 보장해준다.
@Transactional(readOnly = true)
public List<ProductResultDto> getProducts() {
List<Product> entityList = productRepository.findAll();
return entityList.stream()
.map(entity -> modelMapper.toMapping(entity, ProductResultDto.class))
.collect(Collectors.toList());
}
위 메소드는 product의 목록을 조회하기위해 해당 데이터를 요청 하는 메소드이다. 위 메소드가 호출되는 경우 해당 메소드는 아래의 속성을 가지게 된다.
- 연산이 고립되어, 다른 연산과의 혼선으로 인해 잘못된 값을 경우가 방지된다.
- 연산의 원자성이 보장되고, 문제가 발생하면 조회를 하지 않을 것이고, 조회하는 것이 아니라 변경하거나 등록하는 로직인 경우에도 문제가 발생할 경우 변경사항이 커밋되지 않는다.
@Transactional은 어노테이션 기반 AOP를 통해 구현되어있다. 따라서 클래스 또는 메소드에 @Transactional 어노테이션이 선언되면 해당 메소드에 대해 트랜잭션이 적용된 프록시 객체를 생성한다.
이 프록시 객체는 @Transactional이 포함된 본래의 메소드가 호출될 경우 트랜잭션을 시작하고 (CheckedException 또는 예외가 없을 때는)커밋 또는 (UncheckedException 발생 시)롤백 을 수행한다.
@Transactional은 우선순위를 가지고 있다.
Class Method -> Class -> Interface Method -> Interface 순서로 우선순위를 가진다.
보통 공통적인 트랜잭션 규칙은 클래스에, 특별한 규칙은 메소드에 선언하는 식으로 구성할 수 있다.
인터페이스나 인터페이스 메소드에서도 @Transactional 어노테이션을 적용할 수 있지만 인터페이스 기반 프록시에서만 유효한 트랙잭션 설정이 된다.
@Transactional은 두가지 모드를 가지고 있다. Proxy Mode와 AspectJ Mode가 있는데 Proxy Mode가 Default로 설정되어있다.
public 메소드에 적용해야한다. Protected, Private 메소드에서 선언하면 에러가 발생하지는 않지만, 동작하지도 않는다. 또한 @Transactional이 적용되지 않은 Public Method에서 @Transactional이 적용된 Public Method를 호출할 경우, 트랜잭션이 동작하지 않는다.
Non-Public 메서드에 적용하고 싶으면 AspectJ Mode에서 사용할 수 있다.
@Transactional 어노테이션을 아래의 명시된 목록을 설정값으로 받아 적용할 수 있다.
value(String) : 사용할 트랜잭션 관리자
propagation(enum: Propagation) : 사용할 전파 설정
isolation(enum: isolation) : 선택적 격리 수준
readOnly(boolean) : 읽기/쓰기 vs 읽기 전용 트랜잭션
timeout(int(초)) : 트랜잭션 타임 아웃
rollbackFor(Throwable 로부터 얻을 수 있는 Class 객체 배열) : 롤백이 수행되어야하는 선택적인 예외 클래스의 배열
rollbackForClassName(Throwable 로부터 얻을 수 있는 클래스 이름 배열) : 롤백이 수행되어야 하는, 선택적인 예외 클래스 이름의 배열
noRollbackFor(Throwable 로부터 얻을 수 있는 Class 객체 배열) : 롤백이 수행되지 않아야 하는, 선택적인 예외 클래스의 배열
noRollbackForClassName(Throwable 로부터 얻을 수 있는 클래스 이름 배열) : 롤백이 수행되지 않아야 하는, 선택적인 예외 클래스 이름의 배열