해당 포스팅은 OrderService에 있는 주문 취소 메소드를 AdminService로 이동하는 과정에서 발생한 오류와 그 해결 과정에 대해 간략하게 정리해 보고자 한다.
주문 취소 메소드를 OrderService에서 AdminService로 이동시키는 과정에서 오류가 발생했다. 기존에 OrderService에서는 정상적으로 동작하던 주문 취소 메소드가 AdminService에서는 동작하지 않았다. 디버깅을 통해 확인한 결과, Entity를 Dto로 변환하는 과정에서 해당 Entity와 연관된 엔티티를 지연 로딩하여 값을 가져와야 하는데, 값을 가져오지 못해서 오류가 발생했다.
오류 발생 라인은 다음과 같다.
public OrderMngDto(Order order) {
// 생략
this.buyerId = order.getAccount().getUserIdentifier();
}
Order Entity에서 Account Entity를 @ManyToOne(fetch = FetchType.LAZY)로 설정해 놓은 상태였다. 발생한 오류는 지연 로딩된 엔티티를 로딩할 수 없어서 발생한 것으로 확인되었다.
오류를 해결하기 위해 열심히 문제의 원인을 찾다가, @Transactional 애노테이션이 누락된 것을 발견했다. @Transactional 애노테이션을 해당 메소드에 추가함으로써 오류 없이 잘 동작하였다.
JPA에서 fetch = FetchType.LAZY를 사용하면 연관된 엔티티를 지연 로딩할 수 있다. 즉, 연관된 엔티티는 진짜로 사용할 때까지 로딩되지 않고, 필요한 경우에만 DB에서 가져오게 된다.
하지만, fetch = FetchType.LAZY를 사용하는 것만으로는 지연 로딩이 보장되지 않는다. 오히려, 트랜잭션 범위 내에서 지연 로딩이 발생하도록 하려면 트랜잭션을 확실하게 시작하고 종료해야 한다.
이것이 @Transactional 애노테이션의 중요성이다. @Transactional이 없으면 스프링은 서비스 메소드를 실행할 때 트랜잭션을 시작하지 않으며, 결과적으로 JPA의 지연 로딩 설정이 무시될 수 있다. 이렇게 되면 연관된 엔티티가 즉시 로딩되어 성능 문제가 발생할 수 있다.
따라서 fetch = FetchType.LAZY와 같은 지연 로딩 설정을 사용하는 경우에는 해당 서비스 메소드에 @Transactional 애노테이션을 추가하여 트랜잭션을 확실하게 설정하는 것이 좋다. 이렇게 하면 JPA가 연관된 엔티티를 올바르게 지연 로딩할 수 있다.