개요
- JPA에서 엔티티의 데이터를 변경을 함으로써 변경 감지 기능을 통하여 수정 삭제 쿼리를 날릴 수 있지만, 변경 감지 기능은 한 건 씩 진행되기 때문에 여러 건일 경우 성능이 떨어질 수 있다.
- 그렇게 때문에 여러 데이터를 한 번에 업데이트를 시키는 벌크성 수정 쿼리를 이용해야 한다.
스프링 데이터 JPA를 사용한 벌크성 수정 쿼리
@Modifying
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
- 벌크성 수정(Update), 삭제(Delete) 쿼리는 @Modifying 어노테이션을 사용
- 사용하지 않으면 다음 QueryExecutionRequestException 예외 발생
- 벌크성 수정 쿼리는 영속성 컨텍스트를 무시하고 쿼리를 날려 변경 내용으로 DB에 반영한다.
- 그러므로 벌크 연산을 수행 하여도 해당 트랜잭션 안에서의 벌크 연산은 적용되지 않는다.
- 그러므로 벌크성 쿼리를 실행 이 후 조회를 한다면 영속성 컨텍스트를 초기화해야 한다.
- @Modifying(clearAutomatically = true) = entitymanager.clear
스프링 데이터 JPA를 사용한 벌크성 수정 쿼리 테스트
@Test
public void bulkUpdate() throws Exception {
//given
memberRepository.save(new Member("member1", 10));
memberRepository.save(new Member("member2", 19));
memberRepository.save(new Member("member3", 20));
memberRepository.save(new Member("member4", 21));
memberRepository.save(new Member("member5", 40));
//when
int resultCount = memberRepository.bulkAgePlus(20);
//then
assertThat(resultCount).isEqualTo(3);
}
JPQL 사용은 객체지향스럽지 않다?
- SQL을 직접 작성하는 듯한 느낌이 들지만 이 정도의 쿼리는 @Query 어노테이션을 통해 JPQL 을 사용하는 것이 더 간단하고 깔끔하게 사용할 수 있다고 생각한다.
- 이런 간단한 쿼리조차도 Querydsl 이나 JPA Criteria 로 작성하게 된다면 코드가 배가 되므로 배보다 배꼽이 더 커지는 느낌이 든다.
- 물론 동적이거나 조건이 많다면 Querydsl 이나 JPA Criteria 를 사용하는 것이 더 좋아 보인다.