JPA

JPQL - JPQL 기본(5)

방구석 대학생 2020. 11. 16. 19:36

"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."

www.inflearn.com/course/ORM-JPA-Basic#

 

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

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그

www.inflearn.com

 

조인

일반 SQL 과는 다르게 JPQL 은 Entity 를 중심으로 동작한다.

 

- 내부 조인과 외부 조인의 차이?

Member 데이터와 Team 데이터가 있을 때, 내부 조인의 경우 Team 데이터가 없으면 데이터 자체가 검색되지 않으나, 외부 조인의 경우 Team 데이터가 없더라도 Team 데이터는 null 로 표기한 채로 나머지 Member 데이터를 검색해서 반환해준다.

- 세타 조인?

연관관계가 없는 도메인 끼리 일단 테이블을 모두 불러온 다음 특정 조건을 가지고 비교를 해보고 싶을 때 활용할 수 있다.

SQL : select count(m) from Member m, Team t where m.username = t.name

-> 멤버 이름과 팀 이름이 똑같은 경우의 갯수를 센다, 사실상 있을수 없는 경우이다.

 

 

내부 조인(inner join)

아래의 코드를 살펴보자.

- JpaMain.java

Team team = new Team();
team.setName("teamA");
em.persist(team);

Member member = new Member();
member.setUsername("member1");
member.setAge(10);

member.setTeam(team);

em.persist(member);

em.flush();
em.clear();

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

위와 같이 코드를 작성하고 애플리케이션을 실행하면 아래와 같은 Hibernate SQL 을 출력하는 것을 확인할 수 있다.

- Hibernate SQL

Hibernate: 
    /* insert jpql.Team
        */ insert 
        into
            Team
            (name, id) 
        values
            (?, ?)
Hibernate: 
    /* insert jpql.Member
        */ insert 
        into
            Member
            (age, TEAM_ID, username, id) 
        values
            (?, ?, ?, ?)
Hibernate: 
    /* select
        m 
    from
        Member m 
    inner join // 내부 조인이 정상적으로 수행되는 것을 확인할 수 있다. 
        m.team t */ select
            member0_.id as id1_0_,
            member0_.age as age2_0_,
            member0_.TEAM_ID as team_id4_0_,
            member0_.username as username3_0_ 
        from
            Member member0_ 
        inner join
            Team team1_ 
                on member0_.TEAM_ID=team1_.id
Hibernate: /* team 은 아직 사용하지도 않았는데 왜 select 쿼리가 나간것일까? */
    select
        team0_.id as id1_3_0_,
        team0_.name as name2_3_0_ 
    from
        Team team0_ 
    where
        team0_.id=?

 

위의 Hibernate SQL 을 보면 내부 조인이 정상적으로 수행되는 것을 확인함과 동시에, team 객체를 아직 사용하지도 않았는데 갑자기 team 객체에 대해 select 문이 나온것을 확인할 수 있다.

이를 통해 주의해야 할 점으로 무엇을 알 수 있을까?

 

Member 와 Team 과 같은 다대일 연관관계 에서는 지연 로딩을 잘 활용해야 한다.

- Member.java

@ManyToOne(fetch = FetchType.LAZY) // 지연 로딩으로 연관관계를 설정해준다.
@JoinColumn(name = "TEAM_ID")
private Team team;

 

연관관계를 지연로딩으로 설정해준 후 다시 애플리케이션을 실행해보면 아래와 같이 Hibernate SQL 에서 team 객체에 대해 select 쿼리가 전달되지 않는 것을 확인할 수 있다.

- Hibernate SQL

Hibernate: 
    /* select
        m 
    from
        Member m 
    inner join
        m.team t */ select
            member0_.id as id1_0_,
            member0_.age as age2_0_,
            member0_.TEAM_ID as team_id4_0_,
            member0_.username as username3_0_ 
        from
            Member member0_ 
        inner join
            Team team1_ 
                on member0_.TEAM_ID=team1_.id
/* 앞전과는 달리 team 객체에 대한 select 쿼리가 전달되지 않았다. */

 

* 내부 조인을 사용할 경우 inner 키워드는 생략할 수 있다.

하지만 유지 보수의 편의를 위해 되도록이면 생략하지 않고 작성해주는 것이 좋다.

 

 

외부 조인(outer join)

외부 조인을 JPQL 에서 구현하고 싶은 경우 JPQL 을 아래처럼 작성할 수 있다.

String query = "select m from Member m left outer join m.team t"; 
// 여기서 outer 키워드는 생략 가능하다.

- Hibernate SQL

Hibernate: 
    /* select
        m 
    from
        Member m 
    left outer join
        m.team t */ select
            member0_.id as id1_0_,
            member0_.age as age2_0_,
            member0_.TEAM_ID as team_id4_0_,
            member0_.username as username3_0_ 
        from
            Member member0_ 
        left outer join /* 외부 조인이 잘 수행되었다. */
            Team team1_ 
                on member0_.TEAM_ID=team1_.id

 

 

세타 조인

세타조인의 경우 아래와 같이 JPQL 을 작성해줄 수 있다.

- JpaMain.java

String query = "select m from Member m, Team t where m.username = t.name";

- Hibernate SQL

Hibernate: 
    /* select
        m 
    from
        Member m,
        Team t 
    where
        m.username = t.name */ select
            member0_.id as id1_0_,
            member0_.age as age2_0_,
            member0_.TEAM_ID as team_id4_0_,
            member0_.username as username3_0_ 
        from
            Member member0_ cross /* 두 테이블을 크로스(곱해서) 해서 조인한다. */
        join
            Team team1_ 
        where
            member0_.username=team1_.name /* 이후 조건에 맞게 데이터를 검색한다. */

 

다음 글에서는 조인 ON 절 및 조인 대상 필터링에 대해 알아보자.