JPA 쓸 때 편한 기능이 있다.
바로 orphanRemoval이다.
@OneToMany(mappedBy = "folder", orphanRemoval = true)
List<Link> links = new ArrayList<>();
One측에서 orphanRemoval을 걸어두면, one측 엔티티를 지울 때 매핑된 Many들을 모두 같이 지워버릴 수 있다.
마치 게시글과 댓글의 관계를 생각해보면 편하다.
그렇다면, 쿼리는.. 어떻게 나갈까?
먼저, 이해를 돕기 위해 나는
FOLDER - LINK가 1:N으로 매핑되어 있다.
FOLDER를 삭제 할 경우 제일 먼저, FOLDER와 매핑된 LINK를 모두 조회한다.
그리고 매핑 된 링크가 N개라면, N개를 ID를 기반으로 하나하나 지운다.
마지막에 폴더를 지워준다.
아무리봐도 성능상 그냥 큰 손해같았다. 뭔가 머리속에 N+1 문제가 떠오르면서, 그거보다 손해같았다..
내가 코드 몇 줄 덜 짜겠다고 쿼리 한두번이 아닌, N번이 더나가는 문제는 수정해야 했다.
벌크 연산을 사용해보자.
@Query("delete from Link l where l.folder = :folder")
@Modifying(clearAutomatically = true, flushAutomatically = true)
void deleteAllByFolder(@Param("folder") Folder folder);
LinkRepository에 직접 벌크 삭제 쿼리를 작성하자. @Modyfying 애노테이션을 붙여야, 더티체킹 패스하고 바로 우리가 원하는 쿼리가 날아간다.
그렇게 된다면, 영속성 Context는 이 사실을 알지 못한다. 따라서 clear && flush를 해줘 캐시를 초기화해주자.
변경 후엔 잘 작동 할까?
Repository에 쿼리 하나, Service에서 호출 하나 추가해서 아주 단순하게 고쳐졌다.