벌크성 수정 쿼리
이러한 요구사항이 있다. "모든 멤버의 나이를 1씩 증가하라"
한명의 멤버에 대해 나이를 수정하기 위해서는 더티 체킹을 사용하면 되지만 이렇게 다수의 엔티티를 수정하는 것을 벌크성 수정이라 한다.
순수 JPA를 사용하면 아래와 같이 할 수 있다.
import org.springframework.stereotype.Repository;
import study.datajpa.entity.Member;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
import java.util.Optional;
@Repository
public class MemberJPArepository {
@PersistenceContext
private EntityManager em;
public int bulkAgePlus(int age){
return em.createQuery("update Member m set m.age = m.age+1 where m.age >= : age")
.setParameter("age", age)
.executeUpdate(); // executeUpdate
}
}
이를 간단히 테스트해보면 아래와 같다.
@Test
void bulkUpdateAgeTest(){
//given
int age = 20;
//20살 이상인 멤버 30명
for(int i=0; i<30; i++){
Member member = new Member("member"+i, i, null); // (이름, 나이, team)
memberJPArepository.save(member);
}
//when
int resultCount = memberJPArepository.bulkAgePlus(age);
//then
assertThat(resultCount).isEqualTo(10);
}
실행결과 테스트에 성공하였다.
하지만 물론 우리는 data jpa를 사용하여 더 쉽게 벌크 수정이 가능하다.
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import study.datajpa.entity.Member;
import study.datajpa.entity.dto.MemberDto;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
public interface MemberRepository extends JpaRepository<Member, Long> {
// clearAutomatically=true를 하면 영속성 컨텍스트를 비워준다.
@Modifying(clearAutomatically = true) // @Modifying이 있어야 순수 JPA에서 본 executeUpdate를 실행시켜준다.
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
}
@Modifying(clearAutomatically=true) :
만약 위와 같은 update문을 날린 뒤, 트랜잭션을 닫지 않고 바로 update한 멤버를 조회한다면, 조회된 멤버는 age가 +1 되지 않은 상태로 나온다. 이는 위와 같은 벌크 연산은 영속성 컨텍스트를 거치치 않고 바로 쿼리를 날리기 때문이다. 하여 왠만하면 위와 같이
@Modifying(clearAutomatically=true)를 반드시 붙이는 것이 좋다.
또한 어노테이션 @Modifying을 붙여주지 않으면 아래와 같은 에러가 발생하니 반드시 붙여주자.
org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for
이제 data jpa를 사용한 벌크 연산을 테스트해보자.
@Test
void bulkUpdateAgeTest(){
//given
int age = 20;
//20살 이상인 멤버 10명
for(int i=0; i<30; i++){
Member member = new Member("member"+i, i, null); // 이름, 나이, team
memberRepository.save(member);
}
//when
int resultCount = memberRepository.bulkAgePlus(age);
//then
assertThat(resultCount).isEqualTo(10);
}
역시 테스트에 성공한다.
김영한님의 인프런 강의와 PDF를 바탕으로 정리하였습니다.
'JPA > 스프링 DATA JPA' 카테고리의 다른 글
Data JPA 09 JPA Hint (0) | 2022.01.08 |
---|---|
Data JPA 08 @EntityGraph (0) | 2022.01.07 |
Data JPA 06 쿼리 메서드 - 반환타입, 페이징 (0) | 2022.01.06 |
Data JPA 05 쿼리 메서드 - Query, 리포지토리 메서드에 쿼리 정의하기 (0) | 2022.01.05 |
Data JPA 04 쿼리 메서드 - NamedQuery (0) | 2022.01.05 |