JPA에서는 보통 데이터를 변경할 때, 데이터를 영속성 컨텍스트에 가져와 setter 메서드를 통해 변경하면 변경 감지를 통해 DB에 업데이트 쿼리를 수행한다.
만약 한 개의 데이터가 아닌 여러개의 데이터를 변경해야할 때, 모든 데이터를 영속성 컨텍스트로 가져와 데이터 갯수에 맞게 setter 메서드를 통해 변경할 수 있다.
Member member1 = new Member("member1", "silver");
Member member2 = new Member("member2", "silver");
Member member3 = new Member("member3", "silver");
Member member4 = new Member("member4", "silver");
Member member5 = new Member("member5", "silver");
em.persist(member1);
em.persist(member2);
em.persist(member3);
em.persist(member4);
em.persist(member5);
em.flush();
em.clear();
다음과 같이 데이터베이스에 등급이 silver인 멤버가 5개가 저장되어 있다.
// 트랜잭션 시작
Member findMember1 = em.find(Member.class, 1L);
Member findMember2 = em.find(Member.class, 2L);
Member findMember3 = em.find(Member.class, 3L);
Member findMember4 = em.find(Member.class, 4L);
Member findMember5 = em.find(Member.class, 5L);
findMember1.setRank("gold");
findMember2.setRank("gold");
findMember3.setRank("gold");
findMember4.setRank("gold");
findMember5.setRank("gold");
// 트랜잭션 커밋
다음과 같이 5개의 데이터 모두를 영속성 컨텍스트로 가져온 다음에 변경감지를 통해 트**랜잭션이 커밋되는 시점에 데이터를 변경**할 수 있다.
5개의 데이터를 변경하기 위해 각 데이터마다
2줄의 코드가 필요하다.
또한 각 데이터의 변경감지에 따른 update 쿼리가 각각 날라가 총 5개의 쿼리가 필요하다.
하지만 만약 데이터가 5개가 아닌 더 많은 데이터를 변경해야 할때 더 많은 코드가 요구될 것이며, 변경하려는 데이터의 개수만큼 update 쿼리가 나타날 것이다. 비효율적인 방법이다.!
벌크 업데이트란 단건 UPDATE, DELETE가 아닌 다건의 UPDATE, DELETE 연산을 하나의 쿼리로 하는 것을 말한다.
em.createQuery("update Member m set m.rank = 'gold'")
.executeUpdate();
다음과 같이 JPQL를 통해 한방에 모든 멤버 데이터의 등급을 gold로 변경할 수 있다.
코드도 간단할 뿐만 아니라 단 하나의 update 쿼리로 데이터를 변경할 수 있어, 이전 방법보단 성능상 효율적이다.
하지만 벌크 업데이트 사용시 주의해야할 점이 있다.
@Modifying
@Query("Update Member m set m.rank = 'gold'")
int updateRant();
spring data jpa 에서는 @Query를 통해 직접 JPQL문을 작성할 수 있는데, 해당 예시 JPQL문은 벌크 업데이트 쿼리이다. 따라서 @Modifying을 꼭 써줘야하는데, 이는 해당 쿼리 메서드 실행 직후 바로 영속성 컨텍스트를 clear하는 기능을 한다. 따라서 영속성 컨텍스트의 1차 캐시와 관련한 문제를 해결할 수 있다.
벌크 업데이트 사용시, 영속성 컨텍스트를 꼭 클리어하거나 영속성 컨텍스트에 데이터가 없을 때 실행시켜야 한다.
https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
https://www.baeldung.com/spring-data-jpa-modifying-annotation