벌크 연산
- PK를 지정하지 않고 실행하는 update, delete 문 
재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면 어떻게 해야할까?
- 재고가 10개 미만인 상품을 리스트로 조회한다. 
- 상품 Entity의 가격을 10% 증가시킨다. 
- 트랜잭션 커밋 시점에 변경 감지가 동작한다. 
JPA 변경 감지 기능으로 이 모든 과정을 실행하려면 너무 많은 SQL이 나간다. 변경할 데이터가 100건이라면 100번의 update sql을 실행해야 한다.
public class JpaMain {
    public static void main(String[] args) {
        String qlString = "update Product p "
                + "set p.price = p.price * 1.1 "
                + "where p.stockAmount < :stockAmount";
        int resultCount = em.createQuery(qlString)
                .setParameter("stockAmount", 10)
                // 영향받은 Entity 수를 반환한다.
                .executeUpdate();
    }
}- 벌크 연산을 사용하면 쿼리 한 번으로 여러 row를 변경할 수 있다. 
- 즉, 엔티티 여러 개를 수정할 수 있다. 
지원 쿼리
- update 
- delete 
- 하이버네이트는 insert를 지원한다. 
주의사항
- 벌크 연산은 영속성 컨텍스트를 무시하고 DB에 직접 쿼리한다. 
해결 방안
- 영속성 컨텍스트 작업을 하기 전에 벌크 연산을 먼저 실행한다. 
- 혹은 벌크 연산 수행 후에 영속성 컨텍스트를 초기화한다. 

- member 객체 생성 후 직접 flush()를 하지 않아도 벌크 연산 전에 insert 문이 나간다. - JPA 기본 flush 모드인 auto는 commit이나 query가 나가면 flush()를 실행하기 때문이다. 
 

- 문제는 벌크 연산으로 강제 업데이트 한 후, 영속성 컨텍스트에 남아있는 기존 데이터엔 반영이 안된다는 것이다. - member.getAge()를 하면 반영이 되지 않은 상태다. 
 
- flush()는 단지 DB에 반영하는 것이지 영속성 컨텍스트에서 지워지는 건 아니다. 

- 따라서 영속성 컨텍스트 초기화를 한 뒤 새롭게 객체를 가져와야 한다. 
- clear() 한 뒤 기존 데이터 대신 다시 member를 가져오면 제대로 보인다. 

- 초기화를 안 하고 가져오면 여전히 이전 데이터를 가져온다. 
@Modifying

- Spring Data JPA에서도 비슷한 기능을 다양한 옵션과 함께 지원한다. 
Last updated
Was this helpful?