Spring Boot로 영화 예매 웹사이트를 개발하던 도중 겪게 된 문제이다. JPA를 사용하여 영화 상영관의 좌석 데이터를 조회할 때, 두 가지 접근 방식이 있었다.
1.
Auditorium(상영관) 엔티티를 조회한 후, 그 안의 좌석 컬렉션(getSeats())에 접근하는 방식
2.
SeatRepository에 정의된 메서드(findByAuditorium_AuditoriumId)를 사용하여 직접 좌석을 조회하는 방식
JPA에서 조회를 할 때, 연관 엔티티로 접근하는 것과 JpaRepository에 메서드를 생성하여 직접 조회하는 방식의 장단점을 알아보게 되었다.
1. 연관 엔티티 접근 (Auditorium → Seat)
Auditorium auditorium = auditoriumRepository.findById(auditoriumId)
.orElseThrow(() -> NotFoundAuditoriumException.EXCEPTION);
List<Seat> seats = auditorium.getSeats();
Java
복사
장점
•
객체 그래프 탐색의 자연스러움
JPA의 연관관계 매핑을 통해, Auditorium 엔티티 내에 정의된 seats 컬렉션에 접근하는 것이 객체지향적 관점에서 자연스럽다.
•
코드의 간결성
엔티티 내부에 포함된 컬렉션을 바로 사용하므로, 별도의 쿼리 메서드를 정의할 필요가 없다.
단점
•
@OneToMany 관계가 기본적으로 Lazy Loading으로 설정되어 있는 경우, auditorium.getSeats() 를 호출할 때 별도의 쿼리가 발생한다. 이때 N+1 문제가 유발될 수 있다.
•
불필요한 엔티티 조회 가능성
Auditorium 엔티티의 다른 필드는 필요치 않고 좌석 정보만 필요한 경우, Auditorium 전체를 로드하는 것은 오버헤드가 있을 수 있다.
2. Repository 메서드 직접 조회
List<Seat> seats = seatRepository.findByAuditorium_AuditoriumId(auditoriumId);
Java
복사
장점
•
효율적인 데이터 조회
데이터베이스 쿼리에서 직접 조건을 걸어 해당 상영관의 좌석만 조회하기 때문에, 불필요한 데이터를 로드하지 않는다. 대용량 데이터 처리 시 성능 측면에서 유리하다.
•
명시적 의도 표현
메서드 이름 자체에서 “어떤 상영관에 속한 좌석만 조회한다”는 의도가 명확히 드러난다.
•
쿼리 최적화
조건에 맞는 데이터를 직접 조회하기 때문에, 페이징이나 정렬, 추가적인 조건을 적용하기 용이하다.
단점
•
코드 중복 가능성
여러 곳에서 Auditorium 엔티티의 좌석을 조회할 필요가 있다면, 여러 Repository 메서드를 관리해야 할 수 있다.
•
관계의 불일치 위험
엔티티 그래프를 탐색하는 대신 직접 쿼리를 사용하면, 연관관계 매핑의 변경에 따른 Repository 메서드 수정이 필요할 수 있다.
결론
•
엔티티 그래프 탐색은 객체지향적이고 코드가 간결하지만, Lazy Loading 및 N+1 문제에 주의해야 한다.
•
Repository 메서드 직접 조회는 필요한 데이터만 효율적으로 조회할 수 있으며, 명시적 의도를 표현할 수 있지만, 쿼리 최적화 및 유지보수에 신경써야 한다.
좌석 데이터가 많거나 다수의 상영관을 관리해야 한다면 2. Repository 메서드 직접 조회 방식이 더 유리할 수 있다.
지금의 프로젝트는 실제 운용되는 사이트가 아니라 실제 사용자 트래픽이 없고, 많은 양의 데이터를 관리하는 것이 아니다. 하지만 데이터 조회 시, 더 나은 지연률 및 반응성을 보이기 위해 직접 조회하는 방식을 사용하기로 했다.