프로젝트/Recipository

[Dev] 23.02.06. 게시글 삭제 시 query 변경 (feat. modify delete query)

규글 2023. 2. 6. 18:26

이전 게시글에서 회원 탈퇴 시 data를 삭제하는 과정에 대해 작업한 것처럼 기존의 삭제 과정에 대한 query도 변경해볼 것이다. 지난 게시글에서의 작업은 다음과 같았다.

  1. 두 번의 사용자 data를 조회하는 select query 각각 1개 (총 2개)
  2. 삭제하고자 하는 게시글 data를 조회하는 select query 1개 (총 1개)
  3. 타 게시글의 댓글 작성자를 수정하는 update query 1개
    댓글, 게시글의 참조 링크, 게시글 data를 삭제하는 delete query 각 1개 (총 4개)
  4. 삭제할 사용자의 권한을 조회하는 select query 1개
    삭제할 사용자의 권한, 사용자의 data를 삭제하는 delete query 각 1개 (총 3개)

 위 항목에서 동일한 과정을 거쳐야하는 것은 2번의 삭제하고자 하는 게시글 data를 조회하는 select query와 3번의 댓글, 게시글의 참조 링크, 게시글 data를 삭제하는 delete query 만 해당한다. 즉, 회원 탈퇴를 위한 작업 중에 일부의 일부만 사용해도 된다는 의미이다.

 

 현재 삭제 query는 어떻게 동작하고 있을까? 동작하지 않는다. 지난 게시글에서의 작업으로 cascade 옵션을 없애주었기 때문이다.(당장 어제 한 작업인데 생각하지 못하고 테스트부터 돌려본 필자라 민망할 따름이다.)

 

 

작업

RecipeRepository.java

    @Query("select r from Recipe r join fetch r.member where r.contentId = :id")
    Recipe getRecipeByContentId(@Param("id") Long contentId);
    
------------------------------------------------------------------------------------

    @Query("select r from Recipe r where r.contentId in :ids")
    List<Recipe> getRecipeByContentIds(@Param("ids") Collection<Long> ids);
    
    @Modifying
    @Query("delete from Recipe r where r.contentId in :ids")
    int deleteAllByIds(@Param("ids") Collection<Long> ids);

 점선을 기준으로 위쪽은 기존에 게시글 하나의 data를 조회하는 Repository의 method이다. 하지만 현재 작업은 여러 게시글을 삭제하는 경우에 대한 작업을 하고 있다. 게시글을 삭제하기에 앞서 게시글 번호 data를 가진 댓글을 삭제해야 하고 게시글 번호 data를 가진 참조링크를 먼저 삭제해야 하므로, 여러 게시글에 대해 삭제 작업을 하기 위해서는 JPQL 을 활용했을 때 게시글 Entity가 우선적으로 필요하다. 따라서 삭제할 게시글 Entity의 List를 불러올 수 있는 method를 새로 추가했고, id로 게시글 data를 삭제할 수 있는 method를 새로 추가했다.

 

RecipeServiceImpl.java

    @Transactional
    @Override
    public boolean deleteList(List<Long> ids) {
        try {
            List<Recipe> recipeList = recipeRepository.getRecipeByContentIds(ids);
            commentRepository.deleteAllByRecipes(recipeList);
            linkRepository.deleteAllByRecipes(recipeList);
            recipeRepository.deleteAllByIds(ids);

            return true;
        } catch (Exception e) {
            return false;
        }
    }

 왼쪽은 기존에 게시글을 삭제하는 logic이고, 오른쪽은 새로 작업한 logic이다. 넘겨받은 id List로 삭제할 게시글의 Entity List를 조회하고, 해당 List에 대해 댓글 data를 삭제하고 참조링크 data를 먼저 삭제하도록 했다. 이는 회원 탈퇴 시 작성했던 method를 그대로 활용했다. 그리고 마지막으로 작성된 게시글의 id에 대한 삭제 작업이 이루어지도록 했다.

 

 그렇게 해서 동작하는 query 문이다. 선택한 게시글의 목록을 조회하는 select query가 우선 동작하고, 이어서 댓글과 참조링크, 마지막으로 게시글을 삭제하는 delete query가 동작하고서 마무리된다.

 

    @Modifying
    @Query(value = "delete from comment c where c.target_id in :ids", nativeQuery = true)
    void deleteAllByRecipes2(@Param("ids") Collection<Long> ids);

 사실 table에 대한 관점에서는 삭제할 게시글의 목록을 조회할 필요가 없긴 하다. 단순하게 삭제 query 세 개면 되는 것이다. 따라서 이에 대한 query까지 바라지 않는다면, JPQL이 아니라 위와 같은 native SQL을 사용하면 된다. 이때도 주의해야하는 점이 @Modifying annotation을 잊으면 안된다는 것이다.

 

 

 이렇게 게시글을 삭제할 때 수행되는 query를 바꿔보았다. 게시글 여러 개를 삭제할 때와 하나만 삭제할 때를 통합해도 괜찮을 것 같긴 한데, 둘의 차이가 분명한지에 대한 판단이 들지 않아서 우선 그냥 두기로 했다. 바로 이어지는 게시글에서는 게시글을 수정하거나 삭제(사실상 수정)할 때 등의 경우에 동일한 조회 query가 두 번씩 수행되는 상황을 분석하고 작업하려고 한다.

 

 

Reference