JPA는 보통 더티체킹을 이용해서 엔티티 한 개씩 데이터를 변경한다. 그런데 한번에 여러개의 데이터를 업데이트 할때 사용한다.

회원의 나이를 한번에 변경하는 쿼리

순수 JPA

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();
}
@Test
public void bulkUpdate() {
	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));

	int resultCount = memberRepository.bulkAgePlus(20);

	assertThat(resultCount).isEqualTo(3);
}

스프링 데이터 JPA

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

문제

여기 까지는 쉽다. 그러나 JPA에서 이러한 업데이트를 할 때는 조심해야 한다.

벌크 연산은 영속성 컨텍스트를 모조리 무시한다.

@Test
public void bulkUpdate() {
	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));

	int resultCount = memberRepository.bulkAgePlus(20);
	assertThat(resultCount).isEqualTo(3);

	Optional<Member> findMember = memberRepository.findOptionalByUsername("member5");
	assertThat(findMember.get().getAge()).isEqualTo(40);
}