프레임워크(Framework)/JPA

[JPA] JPQL 벌크 연산 - 객체지향 쿼리 언어 JPQL (12)

잇트루 2022. 12. 24. 23:08
반응형
본 내용은 온라인 강의 사이트 인프런의 김영한 님의 강의 내용이 포함되어 있습니다.
'자바 ORM 표준 JPA 프로그래밍 - 기본편'
 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

벌크 연산

엔티티를 수정하려면 영속성 컨텍스트의 변경 감지 기능이나 병합을 사용하고, 삭제하려면 엔티티 매니저의 remove() 메서드를 사용한다.

하지만, 이러한 방법으로 수많은 엔티티를 하나씩 처리하기에는 시간이 오래 걸릴 것이다.

 

예를 들어, 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려는 상황이다.

  • (1) 재고가 10개 미만인 상품을 리스트로 조회한다.
  • (2) 상품 엔티티의 가격을 10% 증가한다.
  • (3) 트랜잭션 커밋 시점에 변경 감지가 동작한다.

이 경우, JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL이 실행된다.

변경된 데이터가 100건이라면 100번의 UPDATE SQL이 실행될 것이다.

 

이러한 문제를 해결하기 위해 한 번에 수정하거나 삭제하는 벌크 연산을 사용한다.

 

벌크 연산 예제

em.createQuery("update Member m set m.age = 20")
        .executeUpdate();

System.out.println("resultCount = " + resultCount);
  • 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
  • executeUpdate()의 결과는 영향받은 엔티티 수를 반환
  • UPDATE, DELETE 지원
  • INSERT(insert into … select, 하이버네이트 지원)

 

 

벌크 연산 주의사항(문제점)

  • 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리한다.
  • 영속성 컨텍스트를 무시하기 때문에 발생할 수 있는 문제점 존재한다.
String query = "select p from Product p where p.name = :name";

// (1) 상품A 조회(상품 A의 가격은 1000원이 가정)
Product productA = em.createQuery(query, Product.class)
        .setParameter("name", "productA")
        .getSingleResult();

// 1000 출력
System.out.println("productA 수정 전 = " + productA.getPrice());

// (2) 벌크 연산 수행으로 모든 상품 가격 10% 상승
em.createQuery("update Product p set p.price = p.price * 1.1")
        executeUpdate();

// (3) 1000 출력, 문제 발생!
System.out.println("productA 수정 후 = " + productA.getPrice());

(1) 가격이 1000원인 상품 A를 조회하여 상품 A는 영속성 컨텍스트에서 관리한다.

(2) 벌크 연산으로 모든 상품의 가격을 10% 상승시켰기 때문에 상품 A의 가격은 1100으로 기대한다.

(3) 하지만, 출력 결과는 기대했던 1100이 아닌 1000이 출력된다.

 

 

벌크 연산 문제점 해결 방법

벌크 연산은 영속성 컨텍스트를 통하지 않고 데이터베이스에 직접 쿼리하기 때문에, 영속성 컨텍스트에 있는 데이터와 데이터베이스에 있는 데이터가 달라질 수 있다.

 

이러한 문제를 해결하기 위한 3가지 방법이 있다.

 

em.refresh() 사용

  • 벌크 연산을 수행한 직후에 상품 A 엔티티를 사용해야 하는 경우 em.refresh() 메서드를 사용하여 데이터베이스에서 상품 A를 다시 조회한다.

 

 

벌크 연산 먼저 실행

  • 가장 실용적인 해결책으로 벌크 연산을 가장 먼저 실행하는 방법이다.
  • 벌크 연산을 먼저 실행하고 나서 상품 A를 조회하면 벌크 연산으로 변경된 상품A를 조회할 수 있다.
  • 이 방법은 JPA와 JDBC를 함께 사용할 때에도 유용하다.

 

 

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

  • 벌크 연산을 수행한 직후에 바로 영속성 컨텍스트를 초기화하여 남아있는 엔티티를 제거한다.
  • 영속성 컨텍스트를 초기화하지 않으면 엔티티를 조회할 때 벌크 연산이 적용되지 않은 엔티티를 조회할 수 있다.
  • 영속성 컨텍스트를 초기화하면 이후 엔티티를 조회할 때 벌크 연산이 적용된 데이터베이스에서 엔티티를 조회한다.

 

 

위 방법들 중에서 가능하면 벌크 연산을 가장 먼저 수행하는 방법을 사용하는 것이 좋다.

상황에 따라 영속성 컨텍스트를 초기화하는 것도 필요하다.

반응형