SpringDataJPA - 벌크성 수정 쿼리

박민수·2023년 11월 14일
0

JPA

목록 보기
18/24
post-thumbnail

벌크성 수정 쿼리

JPA는 엔티티를 가져와서 데이터를 변경하면 트랜잭션 커밋 시점에 변경된 부분을 감지하고 DB에 업데이트 쿼리를 날린다. 이런 경우 데이터 한 건에만 적용된다. 이와 반대로 모든 데이터에 업데이트를 적용하는 쿼리를 벌크성 수정 쿼리라고 한다. (ex: 모든 직원의 연봉을 10% 인상)

순수 JPA 쿼리

SpringDataJPA를 이용한 벌크성 수정 쿼리를 알아보기 전에 먼저 순수 JPA를 이용한 벌크성 수정 쿼리를 알아보고자 한다.

public int bulkAgePlus(int age) {
    int resultCount = em.createQuery(
        "update Member m set m.age = m.age + 1 where m.age >= :age")
        .setParameter("age", age)
        .executeUpdate();
    return resultCount;
}

테스트 코드

@Test
public void bulkUpdate() throws Exception {
    //given
    memberJpaRepository.save(new Member("member1", 10));
    memberJpaRepository.save(new Member("member2", 19));
    memberJpaRepository.save(new Member("member3", 20));
    memberJpaRepository.save(new Member("member4", 21));
    memberJpaRepository.save(new Member("member5", 40));
    
    //when
    int resultCount = memberJpaRepository.bulkAgePlus(20);
    
    //then
    assertThat(resultCount).isEqualTo(3);
}

SpringDataJPA 쿼리

SpringDataJPA를 이용하여 벌크성 수정, 삭제 쿼리를 작성하려면 @Modifying 어노테이션을 사용하면 된다.
사용하지 않으면 예외가 발생한다. (org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations)

@Modifying
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);

테스트 코드

@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);
}

참고: 벌크 연산은 영속성 컨텍스트를 무시하고 실행하기 때문에, 영속성 컨텍스트에 있는 엔티티의 상태와 DB에 엔티티 상태가 달라질 수 있다. 따라서 권장하는 방식은 다음과 같다.

  1. 영속성 컨텍스트에 엔티티가 없는 상태에서 벌크 연산을 먼저 실행한다.
  2. 부득이하게 영속성 컨텍스트에 엔티티가 있으면 벌크 연산 직후 영속성 컨텍스트를 초기화 한다.

영속성 컨텍스트 초기화 방법

영속성 컨텍스트를 초기화 하는 방법은 2가지가 있다.

  1. 영속성 컨텍스트 초기화 옵션 사용 : @Modifying(clearAutomatically = true) (기본값 false)
  2. em.clear(), em.flush()를 이용하여 영속성 컨텍스트 초기화
@Modifying(clearAutomatically = true)
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
@PersistenceContext EntityManager em;

@Test
public void bulkUpdate() throws Exception {
	...
    int resultCount = memberRepository.bulkAgePlus(20);
    em.flush();
    em.clear();
    ...
}

참조
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84/dashboard

profile
안녕하세요 백엔드 개발자입니다.

0개의 댓글