JPQL(3) - 페이징, 조인

2024. 1. 25. 23:42spring/JPA

페이징

JPA는 페이징을 처리하는 API를 제공한다.

- setFirstResult(int startPosition) : 조회 시작 위치

- setMaxResults(int maxResult) : 조회할 데이터 수

 

List<Member> resultList = em.createQuery("select m from Member m order by m.age desc", Member.class)
        .setFirstResult(10)
        .setMaxResults(20)
        .getResultList();

 

위 예제는 11번째부터 시작해서 20건의 데이터를 조회한다.(11~30)

 

 

 

조인

JPQL도 조인을 지원한다. SQL과 거의 동일하고 문법만 약간 다르다.

 

-내부조인

List<Member> resultList =
	em.createQuery("select m from Member m inner join m.team t", Member.class).getResultList();

 

 

select
    member0_.MEMBER_ID as member_i1_6_,
    member0_.age as age9_6_,
    member0_.TEAM_ID as team_id16_6_,
    member0_.USERNAME as usernam10_6_,
from
    Member member0_ 
inner join
    Team team1_ 
        on member0_.TEAM_ID=team1_.TEAM_ID

 

JPQL 내부 조인 구문을 보며 SQL의 조인과 약간 다른 것을 확인할 수 있다.

JPQL 조인은 연관 필드를 사용한다. 여기서 m.team이 연관 필드이다.

 

- FROM Member m : 회원을 선택하고 m 이라는 별칭을 줬다.

- Member m JOIN m.team t : 회원이 가지고 있는 연관 필드로  팀과 조인한다.조인한 팀의 별칭은 t이다.

 

JPQL 은 JOIN 명령어 다음에 조인할 객체의 연관 필드를 사용한다. 다음은 잘못된 예제이다.

List<Member> resultList =
	em.createQuery("select m from Member m inner join Team t", Member.class).getResultList();

 

 

-외부조인

List<Member> resultList =
	em.createQuery("select m from Member m left join m.team t", Member.class).getResultList();
select
    member0_.MEMBER_ID as member_i1_6_,
    member0_.age as age9_6_,
    member0_.TEAM_ID as team_id16_6_,
    member0_.USERNAME as usernam10_6_,
from
    Member member0_ 
left join
    Team team1_ 
        on member0_.TEAM_ID=team1_.TEAM_ID

 

 

 

 

페치 조인

페치 조인은 JPQL에서 성능 최적화를 위해 제공하느 기능이다. 페치 조인을 하면 연관된 엔티티나 컬렉션을 한 번에 같이 조회할 수 있는데 join fetch 명령어로 사용할 수 있다.

select m from Member m join fetch m.team
select
    member0_.MEMBER_ID as member_i1_6_,
    member0_.age as age9_6_,
    member0_.TEAM_ID as team_id16_6_,
    member0_.USERNAME as usernam10_6_,
    team1_.TEAM_ID as team_id1_11_1_,,
    team1_.name as name2_11_1_ 
from
    Member member0_ 
inner join
    Team team1_ 
        on member0_.TEAM_ID=team1_.TEAM_ID

 

위에서의 join 쿼리와 다르게 team 엔티티도 함께 조회해온다.

팀을 지연 로딩으로 설정했다고 해도 회원을 조회할 때 페치 조인을 사용해서 팀도 함께 조회했으므로 프록시가 아닌 실제 엔티티 객체를 반환한다.

 

*주의 fetch join 에서는 m.team 에 별칭을 사용할 수 없다.

 

 

 

페치 조인의 특징과 한계

페치 조인을 사용하면 SQL 한 번으로 연관된 엔티티들을 함께 조회할 수 있어서 SQL 호출 횟수를 줄여 성능을 최적화 할 수 있다.

 최적화를 위해 fetch 전략을 즉시 로딩으로 설정하면 일부에서는 빠를 수 있지만 애플리케이션 전체로 보면 사용하지 않는 엔티티를 자주 로딩하므로 오히려 성능에 안좋을 수도 있다. 따라서 글로벌 로딩 전략은 웬만하면 지연 로딩을 사용하고 꼭 필요할 때 최적화를 하자.

 

* 페치 조인 대상에는 별칭을 줄 수 없다.

- 따라서 SELECT, WHERE, 서브 쿼리에 페치 조인 대상을 사용할 수 없다.

- JPA 표준에서는 지원하지 않지만 하이버네이트를 포함한 몇몇 구현체들은 페치 조인에 별칭을 지원한다. 하지만 별칭을 잘못 사용하면 연관된 데이터 수가 달라져서 데이터 무결성이 깨질 수 있으므로 조심해야 한다.

 

* 둘 이상의 대상에는 별칭을 줄 수 없다.

 

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

- 컬렉션이 아닌 단일 값 연관 필드들은 페치 조인을 사용해도 페이징 API를 사용할 수 있다.

 

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

성능 최적화(2) - 읽기 전용  (0) 2024.02.13
성능 최적화(1) - N+1  (0) 2024.02.07
JPQL(2) - 프로젝션  (0) 2024.01.24
JPQL(1) - 기본 문법  (0) 2024.01.24
JPA - 값 타입  (0) 2024.01.20