본문 바로가기

백엔드/JPA

JPQL 페치조인의 한계, 다양한 쿼리

페치조인의 한계

 - 페치조인은 별칭을 쓰면 안된다.

select t From Team t join fetch t.members m where m.age > 30

이런식으로 하게되면 실제로 team의 멤버보다 적은 수의 결과가 나오게 된다. 이는 JPA에서 의도한 설계가 아니니 지원하지 않는다. 정 이렇게 하고 싶으면 member를 조회하도록 한다. fetch join은 team 조회시 모든 member가 나온다고 가정하고 설계되었다.

 - 둘 이상의 컬렉션은 페치조인 할 수 없다.
 - 컬렉션 페치조인 사용시 페이징이 불가능하다. (다대일 일대일에서는 페치조인해도 페이징이 가능하다)

컬렉션 페치조인은 1의 입장에서는 데이터 뻥튀기 현상이 일어나니 페이징을 사용할 수 없는것이 당연하다. 만약 사용하고 싶으면 다음과 같이 할수는 있다.

이제 result의 getMembers 를 하면서 순회를 하면 지연이든 즉시로딩이든 1+N 문제가 발생할 것이다. 이를 방지하기 위해서 @BatchSize라는 것을 사용하면 된다.

이렇게 하면 한번에 100개를 가져오게 되어서 1+N문제가 어느정도 해결된다.  1 + (N/100) 정도로.

 

페치조인 정리

  • 페치조인은 객체 그래프를 유지할 때 사용하면 좋다.
  • 여러 테이블 조인해서 엔티티가 아닌 다른 모양으로 조회해야한다 -> 일반조인 + DTO 사용하기
  • 모든 것을 페치 조인으로 해결할 수는 없다.

 

JPQL의 다양한 쿼리

🪄 다형성쿼리

JPQL 에서는 상속개념을 반영한 다형성 쿼리가 가능하다. 만약 싱글테이블 전략으로 상속 테이블을 만들었다는 상황에서 아래와 같은 쿼리가 가능하다.

//1
String query = "select i from Item i where treat(i as Book).author = 'kim'"

 

 

그리고 비슷한 기능을 하는 Treat 함수도 있다.

ㅓㄹ크연산이란 쿼리 한번으로 여러 테이블의 로우를

Treat 함수는 SQL 문으로 번역시에 i.DTYPE으로 필터링하는 역할을 한다.

🪄 네임드 쿼리

네임드 쿼리는 JPQL을 미리 정의해서 이름을 붙여두고 사용하는 방식이다.

이런식으로 쿼리에다가 Member.findByUsername이라는 이름을 붙여서 코드 내에서 이름으로만 편하게 사용하는 것이다. 장점이라면 컴파일 시점에 쿼리를 검증하여 에러를 잡아준다는 점이다. 하지만 JPA의 네임드 쿼리는 불편해서 추후에 스프링 데이터 JPA의 네임드쿼리를 배우는 것이 좋다.

🪄 벌크연산

벌크 연산 : 쿼리 한번으로 테이블의 여러 로우의 값을 변경하는 것.

만약 모든 멤버의 나이를 20살로 변경하는 쿼리를 실행한다고 해보자. 그렇게 되면 멤버의 수만큼 update문이 나가게 될 것이다. (1+N번의 쿼리..) 이는 매우 비효율적이므로 벌크연산을 통해 한번에 업데이트하도록 한다.

벌크연산은 이처럼 데이터베이스에 JPQL로 쿼리를 바로 날려버리는 것이다. 이를 통해 영속성 컨텍스트를 거치지 않아서 1+N 문제가 발생하지 않는다. 주의할 점이라면 바로 디비에 날리는 거라서 변경사항이 영속성 컨텍스트에 반영이 되지 않기때문에 위에서 getAge를 통해 나이를 출력해보면 222로 업데이트 되기 전의 나이가 나올 것이다. 그러므로 벌크 연산을 수행한 후에는 꼭 영속성 컨텍스트를 초기화해줘야한다!!

벌크연산 정리

  • 벌크 연산은 업데이트를 한방에 처리해주는 쿼리
  • 영속성 컨텍스트에 반영안되므로 벌크연산 후에는 em.clear를 통해 영속성 컨텍스트를 초기화해줘야한다.

 

 

마무리

JPA 핵심원리 정리 끝..!

 

관련글

 

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

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

www.inflearn.com

 

 

 

'백엔드 > JPA' 카테고리의 다른 글

스프링 데이터 jpa 기본 기능정리  (0) 2021.08.22
스프링 데이터 JPA 기초  (0) 2021.08.22
JPQL 중급문법  (0) 2021.08.08
JPQL 기초  (0) 2021.08.08
JPA 값타입  (0) 2021.08.08