반응형

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 설명 - 

https://stackoverflow.com/questions/43665090/why-do-we-have-to-use-modifying-annotation-for-queries-in-data-jpa

https://docs.spring.io/spring-data/jpa/docs/2.0.4.RELEASE/api/org/springframework/data/jpa/repository/Modifying.html

 

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • shared트위터 공유하기
  • shared
  • 카카오스토리 공유하기