장바구니에 존재하는 상품을 선택하여 주문하기
버튼을 클릭하면, 해당 상품을 주문 상태로 변경하고 장바구니에서 해당 상품들을 제거하는 것이었다.
문제는 장바구니에서 해당 상품들을 제거할 때 발생했다.
장바구니에서 2개 이상의 상품을 선택하여 주문하기
버튼을 클릭하였을 때 주문 서비스를 수행한 후 장바구니에서 해당 상품으들을 제거할 때 개별로 delete
쿼리가 발생했다.
delete
from
cart_item
where
cart_item_id=68
delete
from
cart_item
where
cart_item_id=69
delete
from
cart_item
where
cart_item_id=70
처음 접근한 방식은 Data JPA에서 제공하는 deleteById()
기능을 이용하였다.
@Transactional
public void cancelCartItems(List<Long> cartItemIds) {
cartItemIds.forEach(id -> cartItemRepository.deleteById(id));
}
하위 엔티티를 로딩할때 한번에 상위 엔티티 ID를 지정한 숫자만큼 in Query
로 로딩해주는 default_batch_fetch_size
값을 100으로 설정해 두었기 때문에 한번의 Transactional
에서 발생한 쿼리는 모두 in Query
로 처리되는 것으로 착각하고 있었다.
delete
쿼리가 여러번 발생한 이유는 반복문이 한번 처리될 때마다 한번씩 쿼리를 발생시키기 때문인 것 같다.
forEach()
와 같은 반복문 대신 한번에 값을 처리해줄 방법이 필요했고, Data JPA에서 여러개의 id를 받아 delete
를 처리해주는 deleteAllById()
기능을 적용해보았다.
@Transactional
public void cancelCartItems(List<Long> cartItemIds) {
cartItemRepository.deleteAllById(cartItemIds);
}
In Query
를 통해 한번에 처리될 줄 알았지만 deleteById()
와 마찬가지로 여러번의 delete
쿼리가 발생했다.
Data JPA에서 제공하는 기능이기 때문에 분명히 최적화가 되어 제공될 것이라는 나의 생각이 산산조각 나버렸다.
📒 문제 해결에 도움을 준 고마운 블로그 : [JPA에서 대량의 데이터를 삭제할때 주의해야할 점](https://jojoldu.tistory.com/235)
예상한대로 Data JPA에서 제공하는 deleteAllById()
메서드는 단건 삭제가 기본값이었다.
아래는 참고한 블로그에서 일부 발췌한 내용이다.
여기까지 결과로 알 수 있는 것은 JpaRepository에서 제공하는 deleteByXXX 등의 메소드를 이용하는 삭제는
단건이 아닌 여러건을 삭제하더라도 먼저 조회를 하고 그 결과로 얻은 엔티티 데이터를 1건씩 삭제한다는 것입니다.
즉, 제가 만약 1억건 중 50만건을 삭제한다고 하면 50만건을 먼저 조회후 건건으로 삭제한다는 것입니다.
향로님의 테스트 코드를 통해 deleteByXXX
의 메소드들이 단건으로 삭제되는 것을 확인할 수 있었다.
deleteByXXX
의 메소드의 작동 방식을 확인하는 것만으로 끝나지 않고 직접 삭제 쿼리를 작성하라는 해결 방법까지 제시해 주었다.
@Modifying
@Query("delete from CartItem c where [c.id](http://c.id) in :ids")
void deleteAllByIds(@Param("ids") List<Long> ids);
JPA Repository에 deleteAllByIds()
라는 인터페이스를 생성한 후 @Query
를 통해 직접 삭제 쿼리를 작성하였다.
@Modifying
은 MDL 쿼리가 발생할 때 적용해주는 어노테이션이다.
@Transactional
public void cancelCartItems(List<Long> cartItemIds) {
cartItemRepository.deleteAllByIds(cartItemIds);
}
직접 작성한 삭제쿼리를 CartService
에 적용한 후 테스트를 진행해본 결과 in Query
를 통해 일괄 삭제 쿼리가 발생하는 것을 확인할 수 있었다.
delete
from
cart_item
where
cart_item_id in (68, 69, 70)
***