- JPA에서 벌크 연산은 executeUpdate()를 통해 JPQL에 update, delete를 지원하였다.
- 또한 벌크 연산은 DB에 직접 쿼리를 날리기 때문에 영속성 컨텍스트에 영향을 주지 않았다.
- 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;
}
- 벌크 연산과, 파라미터 바인딩을 통해 JPQL에 update 쿼리를 작성하였다.
- Test 코드
@Test
public void bulkUpdate() {
//given
memberJpaRepository.save(new Member("member1", 10));
memberJpaRepository.save(new Member("member2", 19));
memberJpaRepository.save(new Member("member3", 23));
memberJpaRepository.save(new Member("member4", 21));
memberJpaRepository.save(new Member("member5", 34));
//when
int resultCount = memberJpaRepository.bulkAgePlus(20);
System.out.println("resultCount = " + resultCount);
//then
assertThat(resultCount).isEqualTo(3);
}
- JPA의 경우 정상적으로 update한 것을 확인 할 수 있다.
- 스프링 데이터 JPA를 통한 벌크 수정 쿼리
@Modifying
//(clearAutomatically = true)
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
- 스프링 데이터 JPA의 경우 메서드에 @Modifying를 작성해주어야 executeUpdate를 실행한다. 작성해주지 않을 경우 getResultList, getSingleResult를 실행한다.
- Test 코드
@Test
public void bulkUpdate() {
//given
memberRepository.save(new Member("member1", 10));
memberRepository.save(new Member("member2", 19));
memberRepository.save(new Member("member3", 23));
memberRepository.save(new Member("member4", 21));
memberRepository.save(new Member("member5", 34));
//when
int resultCount = memberRepository.bulkAgePlus(20);
System.out.println("resultCount = " + resultCount);
// em.flush();
// em.clear();
List<Member> result = memberRepository.findListByUsername("member5");
Member member = result.get(0);
System.out.println("member = " + member);
//then
assertThat(resultCount).isEqualTo(3);
}
- 벌크 연산의 경우 기본이 DB에 직접 쿼리를 날리는 것이기 때문에 영속성 컨텍스트에 값은 변경하지 않는다.
- 위와 같이 DB에는 정상적으로 쿼리에 의해 값이 증가하였지만 메모리에서 값을 조회하게 되면 영속성 컨텍스트에 있는 값을 조회하기 때문에 변경 사항이 적용되지 않은 값이 출력되는 것을 확인 할 수 있다.
- 이렇게 되면 데이터의 불일치가 발생하므로 clear()를 통해 영속성 컨텍스트를 비워준 다음 다시 DB로 부터 값을 받아오거나,
@Modifying(clearAutomatically = true)
@Modifying에 옵션을 추가하여 clear가 자동으로 실행되도록 해야한다.
- 즉, @Modifying을 통해 영속성 컨텍스트를 비워주거나, em.clear()를 통해 영속성 컨텍스트를 비워줘야 한다.
출처 : 인프런 - 김영한(실전! 스프링 데이터 JPA)
'Programming > Spring' 카테고리의 다른 글
Spring Data JPA - 사용자 정의 리포지토리 (0) | 2023.07.26 |
---|---|
Spring Data JPA - @EntityGraph (0) | 2023.07.26 |
Spring Data JPA - 페이징과 정렬 (0) | 2023.07.25 |
Spring Data JPA - 쿼리 메소드 (메소드 이름으로 쿼리 생성, @Query) (0) | 2023.07.24 |
Spring Data JPA - 공통 인터페이스 기능 (0) | 2023.07.24 |