노트코드
노트코드
노트코드

블로그 메뉴

  • 홈
  • 이력서
  • 이전 블로그
  • 글쓰기
  • 관리자페이지
  • 분류 전체보기 (57)
    • 코틀린 (2)
      • 실무 프로젝트로 배우는 Kotlin & Sprin.. (2)
    • JAVA (1)
      • 디자인패턴 (1)
      • 객체지향 5대원칙 (0)
    • SPRING (32)
      • JPA (11)
      • 스프링시큐리티 (1)
      • 스프링 (8)
      • QueryDsl (1)
      • 스프링배치 (11)
    • AZURE (0)
    • ETC (10)
      • MAVEN (0)
      • GIT (0)
      • ReMind (3)
      • Exception (1)
      • CS (6)
    • 책 (8)
      • 이것이 자바다 (8)

최근 글

최근 댓글

태그

  • 스프링
  • JPA
전체 방문자
오늘
어제
hELLO · Designed By 정상우.
노트코드

노트코드

SPRING/JPA

[JPA]객체지향 쿼리 심화

2022. 1. 21. 01:46

벌크 연산

엔티티를 수정하여 영속성 컨텍스트의 변경 감지 기능이나 병합을 사용하고 삭제할때 EntityManager.remove() 사용한다. 하지만 이 방법으로 수백개 이상의 엔티티를 하나씩 처리하기에는 시간이 너무 오래걸리고, 이럴 때 여러건을 한 번에 수정하거나 삭제하는 벌크 연산을 사용한다.\

// UPDATE 벌크 연산
String sqlString = "update Product p set p.price = p.price * 1.1 where p.stockAmount < :stockAmount";
int resultCount = em.createQuery(sqlString).setParameter("stockAmount", 10).executeUpdate();

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

// DELETE 벌크 연산
String sqlString = "delete from Product p where p.price < :price";
int resultCount = em.createQuery(sqlString).setParameter("price", 100).executeUpdate();

*벌크 연산의 주의점

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

연산 직전에 상품A에 대해 조회하면 가격 1000원이 영속성 컨텍스트에 관리가 된다.

벌크 연산을 하면 컨텍스트를 거치지 않고, 바로 DB에 접근하게 된다. 이렇게 되면 영속성 컨텍스트 데이터와 DB데이터의 차이가 발생한다.

해결방법

  • em.refresh()사용 벌크 연산을 수행한 직후에 정확한 상품 A 엔티티를 사용해야 한다면 em.refresh()를 사용해 상품 A를 다시 조회한다.
  • 벌크 연산 먼저 실행 가장 실용적인 해결책은 벌크 연산을 가장 먼저 실행한다. 연산이 끝난 데이터를 조회하기 때문에 변경된 데이터를 조회하게 된다.
  • 벌크 연산 수행 후 영속성 컨텍스트 초기화 벌크 연산을 수행한 직후에 바로 영속성 컨텍스트를 초기화해서 영속성 컨텍스트에 남아있는 엔티티를 제거하는 것도 좋은 방법이다

JPQL로 조회한 엔티티와 영속성 컨텍스트

영속성 컨텍스트에 회원1이 이미 있는데 JPQL로 회원1을 조회를 하게되면 새로 조회한 데이터는 버리고 기존의 것을 사용한다.

1.JPQL을 사용해서 조회를 요청한다.

  1. JPQL은 SQL로 변환되어 데이터베이스를 조회한다.
  2. 조회한 결과를 영속성 컨텍스트와 비교한다.
  3. member1은 이미 있으므로 조회한 내용은 버리고 영속성 컨텍스트에 있는 값이 반환대상이 된다.
  4. member2는 없으므로 영속성 컨텍스트에 추가한다.
  5. member1과 member2를 반환한다. (membe1은 기존에 있던 값)

이런 구조로 동작하는 이유는 영속성 컨텍스트는 기본 키값을 기준으로 하기 때문에 새로 조회한 내용을 영속성 컨텍스트에 추가할 수 없으며, 기존 엔티티를 새로 검색한 엔티티로 대체하는 방법은, 기존 엔티티가 수정 중일 경우 문제가 발생할 수 있어서 새로 조회한 내용이 가장 합리적이기 때문이다.

find() vs JPQL

em.find() :메소드는 엔티티를 영속성 컨텍스트에서 먼저 찾고(메모리) 없으면 데이터 베이스에서 찾는다.(1차 캐시)

jpql : 데이터베이스에 SQL을 실행해서 결과를 조회한다.

JPQL과 플러시 모드

프러시는 영속성 컨텍스트의 변경 내역을 데이터베이스에 동기화 하는 작업이다. 플러시를 호출하려면 em.flush()을 직접 호출해도 되지만 보통 플러시 모드에 따라 커밋하기 직전이다 쿼리 실행 직전에 자동으로 플러시가 호출된다. em.setFlushMode(FlushModeType.AUTO) 커밋 또는 쿼리 실행 시(기본값)

em.setFlushMode(FlushModeType.COMMIT);

커밋시에만 플러시

만약 영속성 컨텍스트에 있는 데이터를 수정하였는고, Flush하지 않은 상태에서 JPQL을 호출하게되면, JPQL특성상 영속성 컨텍스트를 먼저 찾아보지 않으므로 수정된 내용을 볼 수가 없다.

'SPRING > JPA' 카테고리의 다른 글

[JPA]MappedSuperClass  (0) 2022.01.21
[JPA] 프록시  (0) 2022.01.21
[JPA]NamedQuery  (0) 2022.01.21
[JPA] 엔티티 직접사용  (0) 2022.01.21
[JPA] 값 타입종류  (0) 2022.01.21
    'SPRING/JPA' 카테고리의 다른 글
    • [JPA]MappedSuperClass
    • [JPA] 프록시
    • [JPA]NamedQuery
    • [JPA] 엔티티 직접사용
    노트코드
    노트코드
    노션 블로그에서 티스토리로 이전공사중

    티스토리툴바