5.onetomany bag오류

강재영's avatar
Dec 16, 2024
5.onetomany bag오류
 
notion image

1. 하이버네이트 ontomany 오류(N+1오류)

1.1 영화에서 상영관을 조인 그리고 상영시간을 조인

@Query("SELECT c FROM Cinema c JOIN FETCH c.screens s JOIN FETCH s.showtimes st WHERE c.id = :id") Cinema mFindCinemaById(@Param("id") Long id);

1.2 에러가 발생 - ontomany를 두번 사용해서 나는 에러

notion image
 

2. 해결1 - 조인을 상영관까지만 함

@Query("select c from Cinema c join fetch c.screens s where c.id=:id") Cinema mFindCinemaById(@Param("id") Long id);
나머지는 lazy로 가져오게 실행함
 

2.1 해결1의 테스트코드

테스트코드
@Test public void mFindCinemaById_test(){ Long id = 1L; Cinema cinema = adminRepository.mFindCinemaById(id); System.out.println("영화관 정보:"); System.out.println("Cinema ID: " + cinema.getId()); System.out.println("Cinema Name: " + cinema.getName()); System.out.println(cinema.getScreens().size()); List<Screen> screens = cinema.getScreens(); System.out.println("상영관 목록:"); for (Screen screen : screens) { System.out.println(" Screen ID: " + screen.getId()); System.out.println(" Screen Name: " + screen.getName()); System.out.println(" ------------"); List<Showtime> showtimes = screen.getShowtimes(); System.out.println("상영시간숫자 : " +showtimes.size()); System.out.println(" 상영시간 목록:"); for (Showtime showtime : showtimes) { System.out.println(" Showtime ID: " + showtime.getId()); System.out.println(" 상영 시작 시간: " + showtime.getStartedAt()); } } }
 

2.2 해결 1의 문제발생

Hibernate: select c1_0.id, c1_0.img_name, c1_0.img_uname, c1_0.name, c1_0.region_id, s1_0.cinema_id, s1_0.id, s1_0.name from cinema_tb c1_0 join screen_tb s1_0 on c1_0.id=s1_0.cinema_id where c1_0.id=? 영화관 정보: Cinema ID: 1 Cinema Name: 서면롯데시네마 5 상영관 목록: Screen ID: 1 Screen Name: 1상영관 ------------ Hibernate: select s1_0.screen_id, s1_0.id, s1_0.movie_id, s1_0.started_at from showtime_tb s1_0 where s1_0.screen_id=? 상영시간숫자 : 3 상영시간 목록: Showtime ID: 1 상영 시작 시간: 2024-09-12 14:00:00.0 Showtime ID: 2 상영 시작 시간: 2024-09-12 16:00:00.0 Showtime ID: 3 상영 시작 시간: 2024-09-12 18:00:00.0 Screen ID: 2 Screen Name: 2상영관 ------------ Hibernate: select s1_0.screen_id, s1_0.id, s1_0.movie_id, s1_0.started_at from showtime_tb s1_0 where s1_0.screen_id=? 상영시간숫자 : 1 상영시간 목록: Showtime ID: 4 상영 시작 시간: 2024-09-12 17:00:00.0 Screen ID: 3 Screen Name: 3상영관 ------------
 
상영시간을 계속 쿼리를 날려서 가지고 온다
추후 이로직이면 영화관안에 상영관이 5개이고 1개의 상영관이 5개의 상영시간테이블을 가지면 25번을 실행한다는 뜻이다 문제가 있다.
 

3.SET 사용

@NoArgsConstructor @Entity public class Cinema { //영화관 테이블 //TODO: 주석추가 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id ; private String imgName; @Column(length = 500) private String imgUname; private String name; @ManyToOne(fetch = FetchType.LAZY) private Region region; @OneToMany(mappedBy = "cinema",fetch = FetchType.LAZY) private List<Screen> screens;
여기서
@OneToMany(mappedBy = "cinema",fetch = FetchType.LAZY) private List<Screen> screens;
여기 List 를 set로 바꾸면 정상작동을한다 즉
@Query("SELECT c FROM Cinema c JOIN FETCH c.screens s JOIN FETCH s.showtimes st WHERE c.id = :id")
위에 커리문을 다시 사용이 가능하게 된다
 
문제는 같이사용하는 엔티티를 set으로 바꾸는건 아닌거같다
 

4.NativeQuery로 만든다

SELECT c.name, scr.name, st.id, st.started_at FROM cinema_tb c JOIN screen_tb scr ON c.id = scr.cinema_id JOIN showtime_tb st ON scr.id = st.screen_id
 
jpql을 사용하지 않고 이경우에는 네이티브로 한번에 가져온다.
Share article

강재영 블로그