유저의 장바구니 비우기 기능을 만들던 도중
public interface CartRepository extends JpaRepository<Cart, Long> {
void deleteAllByUSer(User User);
}
deleteAllByUser를 통해서 장바구니를 초기화 시켰더니
where 문으로 일괄 삭제할 거라 생각했는데 예상과 달리 Cart의 개수만큼 delete 문이 나갔다.
deleteAll()은 for 문을 돌면서 id 값을 하나하나 확인하면서 지운다고 한다.
그래서 해결 방법을 모색해 봤더니 내가 알게 된 방법은 세 가지가 있다.
List<Cart> carts = cartRepository.findAllByUser(user);
cartRepository.deleteAllInBatch(carts);
// cartRepository.deleteInBatch(carts);
where에 or 문을 통해 제거한다.
Repository에는 따로 추가해 주지 않아도 된다.
/* delete
from
Cart x
where
x = ?1
or x = ?2
or x = ?3 */ delete
from
cart
where
id=?
or id=?
or id=?
이런 식으로 쿼리가 나간다.
/**
* Deletes the given entities in a batch which means it will create a single query. This kind of operation leaves JPAs
* first level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this
* method.
*
* @param entities entities to be deleted. Must not be {@literal null}.
* @deprecated Use {@link #deleteAllInBatch(Iterable)} instead.
*/
@Deprecated
default void deleteInBatch(Iterable<T> entities) {
deleteAllInBatch(entities);
}
보면 deleteAllInBatch를 사용하고 있다.
그리고 Deprecated가 걸려있다. 고로, 둘 중엔 DeleteAllInBatch()를 사용하는 게 맞는 것 같다.
위의 설명에서도 그러라고 한다.
List<Cart> carts = cartRepository.findAllByUser(user);
cartRepository.deleteAllByIdInBatch(carts.stream().map(v -> v.getId()).toList());
/* delete
from
Cart x
where
id in :ids */ delete
from
cart
where
id in (?,?,?)
in 쿼리를 통해 나간다. 그러나 id값 list로 변환해 줘야 하는 번거로움이 있다.
위와 마찬가지로 Repository에는 따로 추가해 주지 않아도 된다.
내가 선택한 방법이다.
public interface CartRepository extends JpaRepository<Cart, Long> {
@Modifying // select 외의 쿼리를 사용하기 위해서 필요함
@Query(value = "delete from Cart c where c.user = :user")
void clearCartByUser(User user);
}
cartRepository.clearCartByUser(user);
/* delete
from
Cart c
where
c.user = :user */ delete
from
cart
where
user_id=?
내가 생각한 쿼리로 where 문을 통해 제거한다.
그래서 나는 3번의 방식을 선택했다.
deleteAllInBatch()
deleteAllByIdInBatch()
jpql
정확히는 N+1문제라기보단 N문제인 것 같다.
👍