본문 바로가기

백/spring boot

cascade type 속성 + N+1문제 해결법 결론

cascade=CascadeType.ALL 속성

@Transactional
    public void createPost(PostRequestDto postRequestDto,Long userId){

        //User 객체 가져오기
        User user=userRepository.findById(userId).orElseThrow(()-> new IllegalArgumentException("해당 id의 유저가 존재하지 않습니다."));
        
        //post 엔티티 생성, 저장
        Post newPost=postRequestDto.toPost(user);
        //postRepository.save(newPost);  (불필요)
        
        //MultipartFile을 PostImage로 변환
        List<PostImage> images=postImageService.changeToPostImage(postRequestDto.getImages(), newPost);
        
        //PostImage를 db에 저장
        //postImageService.saveImages(images);  (불필요)
        
        //Post와 image 매핑
        newPost.mapImages(images);

        postRepository.save(newPost);
    }
  • Q. postRepository.save(newPost)를 아직 하지 않은 상태에서도 PostImage와의 연관관계 설정이 가능하고 db에 저장될 때 post의 id가 외래키로 잘 들어가는 이유
  • A. Post가 PostImage를 참조하고 있고(@OneToMany) 이때 cascade = CascadeType.ALL 속성을걸어줘서!
  • Q. postImageService.saveImages(images)로 이미지를 직접 저장하지 않아도 postRepository.save(newPost)로 함께 저장되는 이유
  • A. Post가 PostImage를 참조하고 있고(@OneToMany) 이때 cascade = CascadeType.ALL 속성을걸어줘서! (매핑해줘도 cascade = CascadeType.ALL 속성이 없다면 각각 save 해줘야함)

처음에는 부모 엔티티를 먼저 데이터베이스에 저장한 후 자식 엔티티와의 연관관계를 설정해야 한다고 생각했다. 하지만 Post가 PostImage를 참조하도록 매핑하고, cascade = CascadeType.ALL 옵션을 설정했기 때문에 그렇지 않아도 된다. PostRepository.save(newPost)가 호출되면 JPA는 먼저 부모 엔티티인 Post를 데이터베이스에 저장하고, 이어서 자식 엔티티인 PostImage도 함께 저장한다. 이때 PostImage는 이미 changeToPostImage 메서드에서 Post와의 연관관계가 설정된 상태이므로, Post가 저장된 후 생성된 Post의 ID가 외래키로 PostImage에 저장된 채로 PostImage가 데이터베이스에 저장된다.

만약 cascade = CascadeType.ALL 사용하지 않았다면 코드는아래와 같아야 한다.

postRepository.save(newPost);

List<PostImage> images = postImageService.changeToPostImage(postRequestDto.getImages(), newPost);

postImageService.saveImages(images);

//Post와 image 매핑
newPost.mapImages(images);

postRepository.save(newPost);

N+1 문제 해결법

  • N+1문제 : Lazy 로딩을 하더라도 연관된(매핑된) 엔티티를 get하는 식으로 사용할 때 추가적으로 쿼리가 나가게 된다.
  • 다대일 관계 (Comment에서 Post를 사용) : fetch join 하기
  • 일대다 관계 (Post에서 Images를 사용) : 1) distinct + fetch join or 2) @BatchSize 이용

-> 두 개이상의 List를 fetch join하거나 페이징을 사용할 댄 fetch join 사용이 불가능하므로 @BatchSize를 이용해야 한다. 따라서 일대다 관계에서는 @BatchSize를 이용하는 경우가 많다고 한다.

 

' > spring boot' 카테고리의 다른 글

이미지 업로드 비동기 처리  (0) 2024.10.24
S3에 이미지 업로드 & 삭제  (0) 2024.10.10
Base Entity 구현  (0) 2024.09.29
JPA 관련 문제들 (주로 N+1문제)  (0) 2024.09.29
스프링 빈  (0) 2024.09.29