@Transactional을 붙이면 어떤 일이 일어나는가?
스프링의 @Transactional은 AOP를 기반으로 동작한다. 그리고 AOP의 구현 방식은 프록시에 있다.
스프링이 프록시를 통해 메서드 호출을 가로채고, 트랜잭션의 시작 & 커밋 & 롤백을 대신 처리해준다.
@Transactional의 함정, 내부 호출?
@Service
public class OrderService {
// 트랜잭션 없음
public void processOrder(Order order) {
// 같은 클래스의 메서드를 직접 호출
this.createOrder(order); // 트랜잭션 적용 X !!!
}
@Transactional
public void createOrder(Order order) {
orderRepository.save(order);
}
}
-> processOrder는 this.createOrder를 호출한다.
-> 여기서 this는 프록시 객체가 아닌 실제 객체로, 트랜잭션 로직이 끼어들지 못한다.
따라서, 클래스를 분리하거나 @Autowired로 자기 자신을 주입받아 프록시를 통해 호출해야 한다.
// 권장: 클래스 분리
@Service
@RequiredArgsConstructor
public class OrderFacade {
private final OrderService orderService;
public void processOrder(Order order) {
orderService.createOrder(order); // 프록시를 통해 호출
}
}
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
orderRepository.save(order);
}
}
그렇다면 롤백은 언제 일어나는가?
-> 기본적으로 스프링은 Unchecked Exception(RuntimeException과 그 하위 클래스)에서만 롤백된다.
checked Exception에서도 롤백을 수행하려면?
-> rollbackFor 속성을 사용해야 한다.
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) throws IOException {
orderRepository.save(order);
throw new IOException("파일 처리 실패"); // 롤백 O
}
'개발' 카테고리의 다른 글
| 반복되는 객체 생성 코드, Builder 패턴으로 개선하기 (0) | 2025.12.08 |
|---|---|
| ModulePropertiesUtils로 모듈 별 properties 파일 관리하기 (0) | 2025.11.06 |
| Spring AI에 대해 (0) | 2025.10.10 |
| Kubernetes로 스프링 프로젝트 배포하기 (0) | 2025.10.03 |
| SSG를 사용한 나만의 블로그 만들기 (0) | 2025.09.08 |