가자공부하러!

Hibernate(9) - 응용 문법 ① (경로 표현식, 페치 조인, 다형성 쿼리) 본문

공부/Java

Hibernate(9) - 응용 문법 ① (경로 표현식, 페치 조인, 다형성 쿼리)

오피스엑소더스 2019. 11. 26. 14:29

예제 : https://github.com/HyeongJunMin/SpringBootOnmacOS/tree/master/ex2-jpql-jpa

 

1. 경로표현식

1.1. .(점)을 찍어 객체 그래프를 탐색하는 것

  - 상태 필드 : 단순히 값을 저장하기 위한 필드

    > 경로 탐색의 끝, 더 이상 탐색이 불가능

  - 단일 값 연관 필드 : 엔티티와의 연관관계를 위한 필드

    > 묵시적 내부 조인이 발생하고 추가적인 탐색 가능

    > 묵시적 내부 조인은 성능튜닝에 많은 영향을 주기 때문에 사용하지 않는것이 좋다

    > 예) select m.team.name From Member m 

      - 이 때 m.team까지 단일 값 연관필드이고 m.team.name은 상태필드이다.

      - 실제 쿼리 : select t.id, t.name from Member m inner join Team t on m.TEAM_ID = t.id

  - 컬렉션 값 연관 필드 : 컬렉션과의 연관관계를 위한 필드

    > 묵시적 내부 조인이 발생하고 추가적인 탐색 불가

    > 묵시적 내부 조인은 성능튜닝에 많은 영향을 주기 때문에 사용하지 않는것이 좋다

      - select t.members from Team t

    > from 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능

      - select m from Team t join t.members m

 

2. 페치 조인(Fetch join)

2.1. 페치 조인이란?

  - 글로벌 로딩 전략보다 우선함

  - 글로벌 로딩 전략은 지연 로딩으로 설정해주고 최적화가 꼭 필요할 때에만 페치 조인을 사용하면 베스트

  - 객체 그래프를 유지할 때 사용하면 효과적 : t.member.뭐를 찾아가야 할 때

  - JPQL에서 성능 최적화를 위해 제공하는 기능

  - 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능(쿼리가 두번 나가겠다 싶을 때 한번에 해결)

    > 즉시 로딩

  - 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하는 경우?

    > 일반 조인으로 필요한 데이터만 조회해서 DTO로 반환하는 것이 효과적이다.

2.2. 페치 조인의 한계

  - 페치 조인 대상에는 별칭을 주지 않는 것이 좋다(alias)

    > 페치 조인은 기본적으로 연관된 모든 값을 가져오는 것인데, 그 중 일부만 조작할 때의 상황을 보장하지 않기 때문에 오류가 발생할 가능성이 높다.

  - 둘 이상의 컬렉션은 페치 조인 할 수 없다.

  - 컬렉션을 페치 조인하면 페이징(API)를 사용할 수 없다.

    > 단일 값 연관 필드들은 페치 조인해도 페이징 가능(일대일, 다대일)

    > 하이버네이트는 경고 로그를 남기고 메모리에서 페이징(매우위험)

      - 쿼리는 DB 모든 값 다가져오고 메모리에서 가공 == 위험

2.3. 엔티티 페치 조인

  - 주로 조회성 기능에서 사용된다.

  - 영속성 컨텍스트에 모두 등록된다.(프록시 아님)

  - 예) 회원을 조회하면서 연관된 팀도 함께 조회하고자 할 때

    > select m from Member m join fetch m.team

      - 실행된 SQL : SELECT m.*, t.* FROM MEMBER M INNER JOIN TEAM T ON M.TEAM_ID = T.ID

      - 즉시로딩과 유사하지만 그에 비해 개발자가 원할 때 동적으로 선택할 수 있는 장점 존재

2.4. 컬렉션 페치 조인

  - @OneToMany(일대다 관계)

  - DISTINCT

    > 컬렉션 페치 조인을 그냥 사용하면 컬렉션의 크기만큼 데이터가 커진다.

      - 데이터 왜곡

    > 중복제거 옵션을 통해 컬렉션의 크기를 알맞게 조절할 수 있다.

    > JPQL의 DISTINCT

      - SQL에 DISTINCT 추가 - 같은 식별자를 가진 엔티티 제거해줌

      - 애플리케이션 레벨에서 엔티티 중복 제거

  - 예) 팀을 조회하면서 팀이 갖는 멤버들을 조회하고자 할 때

2.5. BatchSize

  - 지연 로딩의 n+1 문제를 해결하는 방법 중 하나

  - 쿼리를 모아서 날려주는 기능

  - 사용 방법

    > 엔티티가 가지는 일대다 관계 컬렉션에 @BatchSize(size = 숫자)

@BatchSize(size = 5)
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList();

    > xml 설정파일에 글로벌 설정 추가

<persistence ...> <persistence-unit ...> <properties>
	...
    <property name="hibernate.default_batch_fetch_size" value="100"/>
	...
</properties> </persistence-unit> </persistence>

 

 

3. 다형성 쿼리

3.1. 기능

  - 조회 대상을 특정 자식으로 한정

    > 예) Item 중에 Book, Movie만 조회

      - JPQL : select i from Item i where type(i) IN (Book, Movie)

        > 수행되는 쿼리 : select i from i where i.DTYPE in ('B', 'M')

  - 부모를 자식 조건으로 조회(다운캐스팅)

    > 예) Item 중에 Book의 필드인 author조건으로 조회

      - JPQL : select i from Item i where treat(i as Book).author = 'kim'

        > 수행되는 쿼리 : select i.* from Item i where i.DTYPE = 'B' and i.author = 'kim'

 

 

Comments