포스트 아이디를 통해 관련 해시태그를 지우는 코드를 작성했는데 deleteAll()을 사용하지 말라는 피드백을 받아서 해당 부분을 알아보고 고쳐보았다. 아래의 메서드들은 SimpleJpaRepository에 정의되어 있다.
@Override
@Transactional
public void deleteAll() {
for (T element : findAll()) {
delete(element);
}
}
deleteAll()의 내부 구현을 보면 for문을 돌면서 하나하나 삭제 쿼리를 실행한다. 사용하면 안되는 이유를 알 수 있다...
@Override
@Transactional
public void deleteAllInBatch(Iterable<T> entities) {
Assert.notNull(entities, "Entities must not be null");
if (!entities.iterator().hasNext()) {
return;
}
applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities, em)
.executeUpdate();
}
deleteAllInBatch()의 내부 구현 코드이다.
이 때 DELETE_ALL_QUERY_STRING가 정의되어있는 QueryUtils을 살펴보면
public abstract class QueryUtils {
public static final String COUNT_QUERY_STRING = "select count(%s) from %s x";
public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
...
}
delete from %s x를 통해 테이블의 모든 행을 한번에 삭제하는 것을 볼 수 있다.
그리고 deleteAllInBatch()에서 실행되는 applyAndBind()의 구현 코드를 살펴보면
public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {
Assert.notNull(queryString, "Querystring must not be null");
Assert.notNull(entities, "Iterable of entities must not be null");
Assert.notNull(entityManager, "EntityManager must not be null");
Iterator<T> iterator = entities.iterator();
if (!iterator.hasNext()) {
return entityManager.createQuery(queryString);
}
String alias = detectAlias(queryString);
StringBuilder builder = new StringBuilder(queryString);
builder.append(" where");
int i = 0;
while (iterator.hasNext()) {
iterator.next();
builder.append(String.format(" %s = ?%d", alias, ++i));
if (iterator.hasNext()) {
builder.append(" or");
}
}
...
}
이를 or절을 통해 이어붙이는 것을 알 수 있다. 그래도 한번의 쿼리로 삭제되므로 deleeteAllInBatch()를 사용하려 했지만 deleeteAllInBatch()는 매개변수로 엔티티 객체 집합을 받기 때문에 포스트의 아이디값으로 해당 해시태그를 삭제하는 로직에서는 불필요하다고 판단하였다.
그래서 @Query 어노테이션을 사용해서 직접 쿼리문을 작성하는 방법을 채택했다.
@Modifying
@Query(value = "delete from PostHashtag ph where ph.post.id=:postId")
void deletePhByPostId(@Param("postId") Long postId);
Hibernate:
delete
from
post_hashtag
where
post_id=?
의도대로 한 번의 쿼리문으로 해당되는 해시태그가 삭제되는 것을 볼 수 있었다.