일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 목록
- 싱글톤
- 코딩테스트
- Linux
- codingtest
- 프로그래머스
- 로그인
- input태그
- springboot
- 소스트리
- programmers
- 시큐리티 로그인
- 시큐리티 로그아웃
- StyleSheet
- 스프링 부트
- security
- java
- html
- 반복문
- springSecurity
- 시큐리티로그인
- 2차원배열
- 시큐리티
- gradle
- 리눅스
- javascript
- sql
- JAVA11
- css
- Spring boot
Archives
- Today
- Total
JAVAIARY
M:N 다대다 처리 02 본문
1. 영화 목록 출력 처리 - 추가
1) 영화 이미지 추가
중간에 영화 이미지를 함께 결합해 줌
@Query("select m, max(mi), avg(coalesce(r.grade,0)), count(distinct r) from Movie m " +
"left outer join MovieImage mi on mi.movie = m " +
"left outer join Review r on r.movie = m group by m")
Page<Object[]> getListPage(Pageable pageable);


- 영화 목록 10개를 가져오는 쿼리가 1회 실행되고,
- 각 영화의 이미지를 가져오는 쿼리는 각각 실행되기 때문에 총 10번 실행됨
2) N+1 문제
1번의 쿼리로 N개의 데이터를 가져왔는데
N개의 데이터를 처리하기 위해 필요한 추가적인 쿼리가 각 N개에 대하여 수행되는 상황
ex) 1페이지에 해당하는 10개의 데이터를 가져오는 쿼리 1번
+ 10개의 이미지를 가져오는 추가 쿼리 10번 실행 == 총 11번의 쿼리 실행
따라서 중간의 이미지를 1개로 줄여서 처리해준다.
@Query("select m, mi, avg(coalesce(r.grade, 0)), count(distinct r) from Movie m "
+ "left outer join MovieImage mi on mi.movie = m"
+ "left outer join Review r on r.movie = m group by m")
Page<Object[]> getListPage(Pageable pageable);



- 비효율적으로 여러번 실행되는 코드인 max() 처리를 없애고 출력하면 중간에 반복적으로 실행되는 부분 없이, 목록을 구하는 쿼리와 개수를 구하는 쿼리만 실행됨.
3) 특정 영화의 모든 이미지와 평균평점/리뷰 개수 (= 영화 상세페이지) 출력기능 추가
3-1) MovieRepository에 기능 추가
@Query("Select m, mi " +
"from Movie m left outer join MovieImage mi on mi.movie = m " +
"where m.mno = :mno")
List<Object[]> getMovieWithAll(Long mno); // 특정 영화 조회
3번영화는 2개의 리뷰가 있고, 4개의 이미지가 있음
3-2) 테스트 작성
@Test
public void testGetMovieWithAll(){
List<Object[]> result = movieRepository.getMovieWithAll(3L);
System.out.println(result);
for (Object[] arr : result){
System.out.println(Arrays.toString(arr));
}
}
- 특정 영화의 모든 이미지를 불러옴
3-3) 평점, 리뷰 개수 추가
@Query("Select m, mi, avg(coalesce(r.grade, 0)), count(distinct(r)) " +
" from Movie m left outer join MovieImage mi on mi.movie = m " +
" left outer join Review r on r.movie = m" +
" where m.mno = :mno group by mi, m")
List<Object[]> getMovieWithAll(Long mno); // 특정 영화 조회
- group by 영화 이미지
-> 영화 이미지의 개수만큼 데이터를 만듬 - coalesce
- 조회된 값이 null이 아닌 경우 : 조회된 값 반환
- 조회된 값이 null일 경우 : 사용자가 지정한 값(두 번째 파라미터) 반환
4) 특정 영화의 모든 리뷰와 회원의 닉네임
- 영화 리뷰 조회
- 영화 리뷰 등록, 수정/삭제 기능
4-1) 리뷰조회 기능 추가 및 테스트 작성
public interface ReviewRepository extends JpaRepository<Review, Long> {
List<Review> findByMovie(Movie movie);
}
@Test
public void testGetMovieReviews(){
Movie movie = Movie.builder()
.mno(3L)
.build();
List<Review> result = reviewRepository.findByMovie(movie) ;
result.forEach(movieReview ->{
System.out.println(movieReview.getReviewnum());
System.out.println("\t"+movieReview.getGrade());
System.out.println("\t"+movieReview.getText());
System.out.println("\t"+movieReview.getMember().getEmail());
System.out.println("-----------------------------");
});
}
- Review 클래스의 Member에 대한 Fetch 방식이 LAZY 이기 때문에
한 번에 Review 객체와 Member 객체를 조회할 수 없기 때문에 오류 발생 - @Transactional 을 적용하더라도 Review 객체의 getMember().getEmail()을 처리할 때마다 Member객체를 로딩해야하는 문제 발생
- 1) @Query를 이용하여 조인 처리하기
- 2) @EntityGraph 를 이용하여 Review객체를 가져올 때 Member 객체를 로딩하기
💡@EntityGraph
- 엔티티의 특정한 속성을 같이 로딩하도록 표시하는 어노테이션
- 일반적으로 JPA 사용시 연관관계의 Fetch 속성값은 LAZY로 지정하는데,
entitygraph어노테이션을 통해 특정 기능 수행시에만 EAGER 로딩을 하도록 지정할 수 있다. - attributePaths: 로딩 설정을 변경하고 싶은 속성의 이름을 배열로 명시함
- type: @EntityGraph를 어떤 방식으로 적용할 것인지 설정
- Fetch 속성값은 attributePaths에 명시한 속성은 Eager, 그렇지 않은 속성은 LAZY로 처리
- Load 속성값은 attributePaths에 명시한 속성은 Eager, 그렇지 않은 속성은 엔티티 클래스에 명시되거나 기본 방식으로 처리
4-2) @EntityGraph를 적용하여 Member도 같이 로딩할 수 있도록 변경
@EntityGraph 어노테이션 작성 후 테스트 재실행
5) 회원 삭제 문제와 트랜잭션 처리
'Project > 2023.02~ ) Study toy 프로젝트' 카테고리의 다른 글
M : N (다대다) 관계의 설계와 구현 (0) | 2023.04.03 |
---|---|
자잘한 이슈 고치기! (0) | 2023.03.13 |
@RestController와 JSON처리 (0) | 2023.03.13 |
JPQL로 검색하기 (0) | 2023.03.13 |
컨트롤러와 화면 처리 (0) | 2023.03.06 |