deleteAll vs deleteAllInBatch vs @Query

JUNO LIM·2023년 5월 2일

Spring

목록 보기
4/9

포스트 아이디를 통해 관련 해시태그를 지우는 코드를 작성했는데 deleteAll()을 사용하지 말라는 피드백을 받아서 해당 부분을 알아보고 고쳐보았다. 아래의 메서드들은 SimpleJpaRepository에 정의되어 있다.

deleteAll

@Override
@Transactional
public void deleteAll() {

	for (T element : findAll()) {
		delete(element);
	}
}

deleteAll()의 내부 구현을 보면 for문을 돌면서 하나하나 삭제 쿼리를 실행한다. 사용하면 안되는 이유를 알 수 있다...

deleteAllInBatch

@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

그래서 @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=?

의도대로 한 번의 쿼리문으로 해당되는 해시태그가 삭제되는 것을 볼 수 있었다.

profile
개발개발개발자

0개의 댓글