JVM/JPA

객체지향 쿼리 심화

kyoulho 2023. 6. 30. 16:47

벌크 연산

벌크 연산은 수정, 삭제 모두 executeUpdate()를 사용한다. 이 메소드의 반환값은 영향을 받은 엔티티 건수이다.

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

  • em.refesh(entity)
    • 벌크 연산을 수행한 직후에 정확한 상품A 엔티티를 사용해야 한다면 em.refresh()를 사용해서 데이터베이스에서 상품A를 다시 조회하면 된다.
  • 벌크 연산 먼저 실행
    • 가장 실용적인 해결책은 벌크 연산을 가장 먼저 실행하는 것이다. 예를 들어 위에서 벌크 연산을 먼저 실행하고 나서 상품 A를 조회하면 벌크 연산으로 이미 변경된 상품 A를 조회하게 된다. 이 방법은 JPA와 JDBC를 함께 사용할 때도 유용하다.
  • 벌크 연산 수행 후 영속성 컨텍스트 초기화
    • 벌크 연산을 수행한 직후에 바로 영속성 컨텍스트를 초기화해서 영속성 컨텍스트에 남아 있는 엔티티를 제거하는 것도 좋은 방법이다.

 

영속성 컨텍스트와 JPQL

쿼리 후 영속 상태인 것과 아닌 것

JPQL의 조회 대상은 엔티티, 임베디드 타입, 값 타입 같이 다양한 종류가있다.

엔티티만 영속성 컨텍스트에서 관리된다. 임베디드 타입은 값을 변경해도 변경 감지에 의한 수정이 발생하지 않는다.

 

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

JPQL은 항상 데이터베이스에 SQL을 실행해서 결과를 조회한다.

JPQL로 조회한 엔티티는 영속 상태다.

JPQL로 데이터베이스에서 조회한 엔티티가 영속성 컨텍스트에 이미 있으면 JPQL로 데이터베이스에서 조회한 결과를 버리고 대신에 영속성컨텍스트에 있던 엔티티를 반환한다. 이때 식별자 값을 사용해서 비교한다.

언뜻 보면 2번이 합리적인 것 같지만, 영속성 컨텍스트에 수정 중인 데이터가 사라질 수 있으므로 위험하다.

 

 

JPQL과 플러시 모드

플러시는 영속성 컨텍스트의 변경 내역을 데이터베이스에 동기화하는 것이다.

JPA는 플러시가 일어날 때 영속성 컨텍스트에 등록, 수정, 삭제한 엔티티를 찾아서 INSERT, UPDATE, DELETE SQL을 만들어 데이터베이스에 반영한다.

플러시를 호출하려면 em.flush() 메소드를 직접 사용해도 되지만 보통 FlushMode에 따라 커밋하기 직전이나 쿼리 실행 직전에 자동으로 플러시가 호출된다.

em.setFlushMode(FlushModeType.AUTO);   // 커밋 또는 쿼리 실행 시 플러시(기본값)
em.setFlushMode(FlushModeType.COMMIT); // 커밋시에만 플러시

 

플러시 모드와 최적화

FlushModeType.COMMIT 모드는 트랜잭션을 커밋할 때만 플러시하고 쿼리를 실행할 때는 플러시하지 않는다. 때문에 데이터 무결성에 심각한 피해를 줄 수 있다. 

그럼에도 플러시가 너무 자주 일어나는 상황에 이 모드를 사용하면 쿼리시 발생하는 플러시 횟수를 줄여 성능을 최적화할 수 있다.

JDBC를 함께 사용할 때도 JDBC 쿼리 실행 직전에 플러시를 호출해서 동기화하는 것이 안전하다.

728x90

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

스프링 데이터 JPA와 QueryDSL 통합  (0) 2023.07.02
스프링 데이터 JPA  (0) 2023.07.02
스토어드 프로시저(JPA 2.1)  (0) 2023.06.30
네이티브 SQL  (0) 2023.06.30
QueryDSL  (0) 2023.06.28