테스트 코드 관련 강의를 보다가 deleteAllInBatch() 에 대해서 알게 되었다. 해서 기존에 사용하고 있던 deleteAll() 과의 차이점을 정리해보려한다.
deleteAll() 과 deleteAllInBatch()
User 데이터를 10개 추가해두고 deleteAll() 과 deleteAllInBatch() 를 사용했을 때 각각을 비교해보자.
( UserRepository 는 JPARepository 를 상속받고 있다. )
deleteAll()
deleteAll() 은 CrudRepository 내 정의 되어있는 기능으로 모든 엔티티를 삭제할 때 사용한다.
쿼리를 통해 확인한 내부 동작은 아래와 같다.
1. 작업을 수행하기 전 엔티티를 영속성 컨텍스트로 로드하기위해 select 쿼리를 실행한다.
2. 이후 모든 엔티티들에 대해 개별적으로 delete 쿼리가 실행된다.
- UserRepotitoryTest
@SpringBootTest
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@AfterEach
void tearDown() {
userRepository.deleteAll();
}
..
}
- 실행 결과
deleteAllInBatch()
deleteAllInBatch() 는 JPARepository 에 정의되어있는 기능으로 이 또한 모든 엔티티를 삭제할 때 사용한다.
다만 deleteAll() 은 where 조건을 통해 엔티티를 개별적으로 삭제했다면 deleteAllInBatch() 는 where 절 없이 모든 entity 를 삭제한다.
- UserRepotitoryTest
@SpringBootTest
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@AfterEach
void tearDown() {
userRepository.deleteAllInBatch();
}
..
}
- 실행 결과
deleteAll() vs deleteAllInBatch()
그럼 이 둘 중 무엇을 써야할까?
단순히 생각해보자면 용도 자체가 삭제를 하기위함이니 굳이 select 작업을 거치는 deleteAll() 을 써야할까 하는 생각이 들었다. 이번에는 User 데이터를 1000 개 넣어두고 각 기능별로 삭제에 걸리는 시간을 확인해 보았다.
- UserRepositoryTest
@SpringBootTest
class UserRepositoryTest {
..
@Test
void deleteAllTest() {
userRepository.deleteAll();
}
@Test
void deleteAllInBatchTest() {
userRepository.deleteAllInBatch();
}
}
- 실행 결과
실행 결과 3초 가량의 차이가 발생하며 나는 테스트 실행 이후 데이터를 삭제하는 작업을 처리하기 위한 용도로 사용하기 위함이었기 때문에 deleteAll() 을 deleteAllInBatch() 로 변경하여 사용하였다.
대량의 데이터를 삭제하는 경우에는 deleteAllInBatch() 가 더 유용한 듯 한데, 그런데 이 데이터도 몇 만개를 넘어갈 정도로 많게 되면 너무 많은 시간이 걸릴 수 있다.
이럴 때는 deleteAllInBatch(Iterable<T> entities) 및 deleteAllByIdInBatch(Iterable<ID> ids) 를 활용하여 데이터를 나눠 하위 배치로 삭제하는 것이 유용할 수 있다. ( 참고 문서 )
그렇다면 deleteAll() 은 언제 사용하는 것이 좋을까 ?
deleteAll() 은 대량의 데이터를 처리할 때 성능 저하를 일으킬 수 있지만 영속성 컨텍스트에서 엔티티 상태를 관리하기 때문에 데이터 일관성을 정확하게 관리해야하는 경우 사용하는 것이 좋다.
또한, 콜백 함수(@PreRemove 및 @PostRemove 등) 를 사용한 경우 deleteAllInBatch() 로 트리거되지 않기 때문에 이러한 경우에는 deleteAll() 을 사용해야 한다.
정리
대량의 데이터를 삭제해야하는 경우에는 deleteAllInBatch() 가 유용하겠지만 연관된 엔티티를 삭제하거나 이벤트 리스너나 콜백을 사용하는 경우에는 deleteAll() 을 사용해야 할 수 있다.
참고
https://www.baeldung.com/jpa-entity-lifecycle-events
https://asyncq.com/spring-data-jpa-deleteallinbatch-methods-explained
'Web' 카테고리의 다른 글
[Spring] Mapstruct Mapper Custom with Qualifier, @DecoratedWith (0) | 2024.04.28 |
---|---|
[Spring] Logback MDC 로 애플리케이션 로깅하기 (0) | 2024.04.20 |
[JPA] @ColumnDefault 이해하기 (0) | 2024.01.28 |
[Spring] Soft Delete with JPA (0) | 2024.01.14 |
[Spring] QueryDsl 로 동적 쿼리 짜기 with JPA (0) | 2024.01.07 |