✔ 객체지향 쿼리 심화

1. 벌크 연산

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

하지만 이 방법으로 수백개 이상의 엔티티를 하나씩 처리하기에는 시간이 너무 오래걸린다.

이럴 때 여러 건을 한 번에 수정하거나 삭제하는 벌크 연산을 사용하면 된다.

//UPDATE 벌크 연산String qlString ="UPDATE Product p " +"SET p.price = p.price * 1.1 " +"WHERE p.stockAmount < :stockAmount";int resultCount = em.createQuery(qlString)                    .setParameter("stockAmount", 10)                    .executeUpdate();

벌크 연산은 executeUpdate() 메소드를 사용한다. (벌크 연산으로 영향을 받은 엔티티 건수 반환)

삭제도 같은 메소드를 사용한다.

//DELETE 벌크 연산String qlString ="DELETE FROM Product p "+"WHERE p.price < :price";int resultCount = em.createQuery(qlString)                    .setParameter("price", 100)                    .executeUpdate();

벌크 연산의 주의점

벌크 연산을 사용할 때는 벌크 연산이 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리한다는 점에 주의해야 한다.

벌크 연산시 발생할 수 있는 문제

//DB에 가격이 1000원인 상품A가 있다.//상품A(productA) 조회 (1000원) ...1Product productA = em.createQuery("SELECT p FROM Product p WHERE p.name = :name", Product.class)                    .setParameter("name", "productA")                    .getSingleResult();//출력 결과: 1000System.out.println("productA 수정 전 = " + productA.getPrice());//벌크 연산 수행으로 모든 상품 가격 10% 상승 ...2em.createQuery("UPDATE Product p SET p.price = p.price * 1.1").executeUpdate();//출력 결과: 1000 ...3System.out.println("productA 수정 후 = " + productA.getPrice());
  1. 가격이 1000원인 상품A를 조회했다. 조회된 상품A는 영속성 컨텍스트에서 관리된다.
  2. 벌크 연산으로 모든 상품의 가격을 10% 상승시켰다. 상품A의 가격은 1100원이 되어야 한다.
  3. 벌크 연산 후 상품A의 가격이 기대했던 1100원이 아니고 1000원이 출력된다.