Posts [자바 ORM 표준 JPA 프로그래밍-기본편] 벌크 연산
Post
Cancel

[자바 ORM 표준 JPA 프로그래밍-기본편] 벌크 연산

본 포스팅은 인프러의 JPA 기본편을 수강하고 정리하는 내용입니다.


JPQL - 벌크 연산

일반적인 여러 객체에 대한 업데이트나 delete문이라 생각하면 된다.

  • 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?
  • JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL 실행
    • 1)재고가 10개 미만인 상품을 리스트로 조회한다.
    • 2)상품 엔티티의 가격을 10% 증가한다.
    • 3)트랜잭션 커밋 시점에 변경감지가 동작한다.
  • 변경된 데이터가 100건이라면 100번의 UPDATE SQL 실행

벌크 연산 예제

  • 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
  • executeUpdate()의 결과는 영향받은 엔티티 수 반환
  • UPDATE, DELETE 지원
  • INSERT(insert into .. select, 하이버네이트 지원)
1
2
3
4
5
6
7
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();

벌크 연산 주의

  • 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리
  • 이로 인해 잘못하면 꼬일수가 있다.
  • 해결책은 두 가지가 있다.
    • 1)벌크 연산을 먼저 실행(플러시가 자동으로 됨, 쿼리가 나가는거기에)
    • 2)벌크 연산 수행 후 영속성 컨텍스트만 초기화(벌크 연산 수행해서 전 직원의 연봉이 1억인데 애플리케이션에는 7000만원으로 되있다? 문제가 되기에 초기화해준다) ~~~ Team teamA = new Team(); teamA.setName(“teamA”); em.persist(teamA);

    Team teamB = new Team(); teamB.setName(“teamB”); em.persist(teamB);

    Member member1 = new Member(); member1.setUsername(“회원1”); member1.setAge(10); member1.setType(MemberType.ADMIN); member1.changeTeam(teamA); em.persist(member1);

    Member member2 = new Member(); member2.setUsername(“회원2”); member2.setAge(10); member2.setType(MemberType.ADMIN); member2.changeTeam(teamA); em.persist(member2);

    Member member3 = new Member(); member3.setUsername(“회원3”); member3.setAge(10); member3.setType(MemberType.ADMIN); member3.changeTeam(teamB); em.persist(member3);

    em.flush(); em.clear();

    int resultCount = em.createQuery(“update Member m set m.age = 20”) .executeUpdate();

    // em.clear(); // 그래서 여기서 영속성 컨텍스트를 초기화해줘야한다. 만약 find()로 다시 불러와도 1차 캐시에 있는 데이터를 가져오기에 반영이 안된다.

    System.out.println(“resultCount = “ + resultCount);

    System.out.println(“age = “ + member1.getAge()); // age = 10 (영속성 컨텍스트에 있는게 그대로 나온다) System.out.println(“age = “ + member2.getAge()); // age = 10 (영속성 컨텍스트에 있는게 그대로 나온다) System.out.println(“age = “ + member3.getAge()); // age = 10 (영속성 컨텍스트에 있는게 그대로 나온다) ~~~

추가적으로

Spring Data JPA에서 @ModifyingQuery 어노테이션을 활용하면 영속성 컨텍스트를 깔끔하게 초기화해준다.

This post is licensed under CC BY 4.0 by the author.

[자바 ORM 표준 JPA 프로그래밍-기본편] Named 쿼리

[Java] 일급 컬렉션