공부 기록/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