공부 기록/Spring

[Spring] @Transactional 어노테이션

뵤옹 2023. 4. 3. 16:20

@Transactional 어노테이션

  • @Transactional 어노테이션은 DB와 관련된, 트랜잭션이 필요한 서비스 클래스 혹은 메서드에 해당 어노테이션을 달아주면 된다.
  • 클래스, 메서드 모두에 어노테이션을 붙이면 메서드 레벨의 @Transactional 선언이 우선 적용된다.
  • @Transactional이 붙은 메서드는 메서드가 포함하고 있는 작업 중, 하나라도 실패할 경우 전체 작업을 취소한다.

  • 소스코드에 직접 트랜잭션 관련 로직을 넣어두지 않고 비즈니스 로직에서 완전히 분리할 수 있다.
  • 트랜잭션 코드를 중복해서 사용하지 않아도 되며 유지보수가 유용해진다.

트랜잭션이 롤백되지 않는 경우

1. WebEnvironment의 RANDOM_PORT, DEFINED_PORT 사용

  • WebEnvironment의 RANDOM_PORT, DEFINED_PORT를 사용하면 실제 테스트 서버는 별도의 스레드에서 테스트를 수행하기 때문에 트랜잭션이 롤백되지 않는다.

 

2. 식별자(id)

  • insert 작업을 할 때 식별자(id)가 자동으로 증가하도록 Auto Increment 옵션을 적용할 경우, 트랜잭션에 포함된 insert 작업으로 인해 증가한 id는 트랜잭션이 롤백되어도 감소하지 않는다.
  • Why?
    Auto Increment 옵션은 트랜잭션의 범위 밖에서 동작하기 때문
  • Auto Increment 옵션이 트랜잭션의 범위 밖에서 동작하는 이유는 사이트의 회원가입을 생각하면 이해하기 쉽다.
  • 여러 사람이 동시에 한 사이트에 회원가입을 할 경우,
    중복된 아이디 혹은 올바르지 않은 양식의 아이디 입력 등 여러 요인으로 인해 트랜잭션이 실패하거나 성공한다.
  • 각 트랜잭션이 다른 사람의 회원가입 트랜잭션 성공여부를 기다렸다 id 값을 부여받기에는 얼마나 시간이 걸릴지 모르기 때문에 트랜잭션과 별도로 동작한다.

사용시 주의점

1. 우선순위

  • @Transactional 어노테이션의 우선순위는 왼쪽으로 갈수록 낮아진다.
  • 클래스 메소드 → 클래스 → 인터페이스 메소드 → 인터페이스
  • 어노테이션을 적용할 때 인터페이스보다 클래스에 적용할 것을 권고한다.
  • Why?
    • 인터페이스 기반 프록시에서만 유효한 트랜잭션 설정이 된다.
    • 자바 어노테이션은 인터페이스로부터 상속되지 않기 때문에 클래스 기반 proxy 또는 AspectJ 기반에서 트랜잭션 설정을 인식할 수 없다.

2. 트랜잭션의 모드

  • @Transactional가 갖고 있는 Proxy Mode와 AspectJ Mode 중 Proxy Mode가 Default로 설정되어 있다.
  • 하지만 Proxy Mode는 다음과 같은 경우 동작하지 않는다.
    • 반드시 public 메서드에 적용되어야 한다.
    • protected, private 메서드에서는 선언되어도 에러가 발생하진 않지만 작동하지 않는다.
    • non-public 메서드에 적용하고 싶다면, AspectJ Mode를 고려해야 한다.
    • @Transactional이 적용되지 않은 public 메서드에서 @Transactional이 적용된 public 메서드를 호출할 경우, 트랜잭션이 동작하지 않는다.

 

 


참조

https://tecoble.techcourse.co.kr/post/2021-05-25-transactional/

https://velog.io/@betterfuture4/Spring-Transactional-%EC%B4%9D%EC%A0%95%EB%A6%AC

https://imiyoungman.tistory.com/9