JPA Repository를 이용한 레코드 삭제
레코드를 삭제하는 코드를 작성하다 보면 1:N의 관계에서 1의 id를 가지고 N의 레코드를 삭제할 때가 있습니다.
JpaRepository에서 team과 teamMember의 관계를 예로 들어 아래처럼 코드를 짤 수 있습니다.
fun deleteAllByTeamId(teamId: UUID)
물론 제대로 동작도 합니다. 다만 이 코드는 과도한 성능이 필요할 수 있는 위험을 내포하고 있습니다.
만약 해당 팀의 멤버가 10000명이라면 어떻게 될까요? 그러면 아래처럼 무수한 delete 쿼리가 DB 서버로 날아가게 됩니다.
// pseudo code
select teamMember by teamId
delete teamMember1
delete teamMember2
delete teamMember3
....
delete teamMember10000
이는 JpaRepository 인터페이스의 delete~ 함수는 기본적으로 BulkDelete를 지원하지 않기 때문입니다.
여기서 JpaRepository를 이용한 해결 방법은 2가지가 있습니다.
무수한 delete 쿼리 해결 방법 2가지
1. 기본 함수인 deleteInBatch(Iterable<T> entities) 이용 : 좋은 방법이지만 삭제하고자 하는 Entity들을 메모리상에 가져와서 호출해야 하는 단점이 존재합니다.
2. @Modifying 이용 : 자유롭게 조건을 설정하여 단 한 번의 쿼리로 Bulk Delete를 할 수 있습니다.
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("DELETE FROM TeamMemberEntity tm WHERE tm.teamId = :teamId")
fun deleteAllByTeamId(teamId: UUID): Int
// 그러면 아래처럼 단 1개의 쿼리로 동작
delete
from
TEAM_MEMBER
where
teamId=?
@Modifying 이용 시 주의사항
@Modifying 어노테이션을 이용할 때는 clearAutomatically, flushAutomatically boolean 파라미터를 true로 설정하는 것을 권장합니다.
물론 항상 적절한 방법은 아니기 때문에 실제 Entity 객체가 관리되는 Persistence Context를 고려하여 파라미터 셋팅을 잡아줘야 합니다.
clearAutomatically, flushAutomatically 값을 기본값인 false로 설정하게 되면 한 트랜잭션 내에서 아래 같은 상황에 직면할 수 있습니다.
A를 가져옴
Modifying을 통해서 A를 수정함
A를 가져옴 (변경되지 않은 결과가 나옴)
자세한 내용은 아래 "JPA Repository 함수에 이용되는 Modifying Annotation 설명" 스택 오버플로우 링크를 참고하시기 바랍니다.
참고 문헌
JPA에서 대량의 데이터를 삭제할때 주의해야할 점 - https://jojoldu.tistory.com/235
JPA Repository 함수에 이용되는 Modifying Annotation 설명 -
'JPA(Hibernate)' 카테고리의 다른 글
[JPA] Inheritance bulk-id delete (0) | 2022.02.14 |
---|---|
[JPA] Kotlin final class에 Lazy association이 먹히지 않는 현상 해결법 (0) | 2019.11.08 |
[JPA] paging fetch join 시 유의사항 (0) | 2019.11.08 |