11. 객체지향 쿼리 언어 - 중급 문법 (벌크 연산)

HotFried·2023년 10월 5일

벌크 연산

PK를 지정해서 한건의 update, delete SQL을 실행하는 것 이외의 upeate, delete SQL

Question) 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?

  • JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL 실행
    • 1. 재고가 10개 미만인 상품을 리스트로 조회한다.
    • 2. 상품 엔티티의 가격을 10% 증가한다.
    • 3. 트랜잭션 커밋 시점에 변경감지가 동작한다.
    • 변경된 데이터가 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();
    }
}
  • 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
  • executeUpdate()의 결과는 영향받은 엔티티 수 반환
  • UPDATE, DELETE 지원
  • INSERT(insert into .. select, 하이버네이트 지원)

주의사항

  • 벌크 연산은 영속성 컨텍스트를 무시하고 DB에 직접 쿼리한다.

해결방안

-> 벌크 연산을 먼저 실행

-> 벌크 연산 수행 후 영속성 컨텍스트 초기화

  1. 처음 회원 등록 시 회원의 나이를 0으로 설정하고 영속상태로 만들었다.

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

  3. 벌크 연산으로 강제 업데이트 했지만, 영속성 컨텍스트에 있는 기존 엔티티에는 반영이 되지 않는다.
    -> 벌크 연산으로 회원의 나이를 20살로 강제 설정하였다.
    -> 하지만 member.getAge() 코드를 실행해도 결과는 0살이 나올 것이다.
    ∴벌크 연산 수행 후 영속성 컨텍스트를 반드시 초기화 해야한다.


참고 :

김영한. 『자바 ORM 표준 JPA 프로그래밍』. 에이콘, 2015.

자바 ORM 표준 JPA 프로그래밍 - 기본편

profile
꾸준하게

0개의 댓글