본문 바로가기
  • 개발공부 및 일상적인 내용을 작성하는 블로그 입니다.
JPA

JPQL - JPQL 기본(2)

by 방구석 대학생 2020. 11. 15.

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

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

 

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

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

www.inflearn.com

 

프로젝션

- SELECT 절에 조회할 대상을 지정하는 것으로 그 대상으로는 Entity, Embedded type, Scala type(숫자, 문자등 기본 데이터 타입) 이 있다.

 

1. Entity 프로젝션의 경우

- JpaMain.java

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

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

List<Member> result = em.createQuery("select m from Member m", Member.class)
						.getResultList();
                        
Member findMember = result.get(0);
findMember.setAge(20);

 

코드를 위와 같이 작성해서 Entity 를 검색하여 List 컬렉션에 Entity 데이터들이 반환되는 경우, 해당 데이터들은 영속성 컨텍스트에서 관리를 해줄까?

 

애플리케이션을 실행해보면 아래와 같은 Hibernate SQL 을 출력하는 것을 볼 수 있다.

- Hibernate SQL

Hibernate: 
    /* select
        m 
    from
        Member m */ 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_
Hibernate: 
    /* update
        jpql.Member */ update
            Member 
        set
            age=?,
            TEAM_ID=?,
            username=? 
        where
            id=?

 

위의 Hibernate SQL 을 보면 update query 가 실행되고 있음을 볼 수 있다.

즉, Entity 프로젝션을 하면 검색된 Entity 대상이 몇개가 됐든 전부 다 영속성 컨텍스트에서 관리된다는 것을 알 수 있다.

아래와 같이 JPQL 을 작성해도 Entity 프로젝션 으로서 영속성 컨텍스트에 관리된다.

- JpaMain.java

// 테이블 inner 조인 Entity 프로젝션
List<Team> result = em.createQuery("select m.team from Member m", Team.class)
						.getResultList();

또한 위의 코드를 실행하면 테이블 조인 쿼리가 나가게 된다.

(연관관계를 가지고 있는 서로 다른 도메인 테이블의 데이터를 가져오므로)

- Hibernate SQL

Hibernate: 
    /* select
        m.team 
    from
        Member m */ select
            team1_.id as id1_3_,
            team1_.name as name2_3_ 
        from
            Member member0_ 
        inner join /* 테이블 inner 조인 */
            Team team1_ 
                on member0_.TEAM_ID=team1_.id

 

그런데 겉으로 보기에는 위와 같이 코드를 작성하면 좋아보이나, 테이블 조인 기능을 활용할 땐 웬만하면 SQL 과 비슷하게 작성해 주어야 한다.

테이블 조인 자체가 성능에 영향을 끼칠 가능성이 다분하다, 그렇기 때문에 한눈에 보이도록 코드를 작성해주는 것이다.

(쉽게 말해, 어느 타이밍에 테이블 조인이 발생하는지 쉽게 예측이 가능해진다.)

- JpaMain.java

List<Team> result = em.createQuery("select t from Member m join m.team t". Team.class)
						.getResultList(); // 테이블 inner 조인을 직접 작성해준다.

 

- Hibernate SQL

Hibernate:  /* 주석만 다르게 나왔다. */
    /* select
        t 
    from
        Member m 
    join
        m.team t */ select
            team1_.id as id1_3_,
            team1_.name as name2_3_ 
        from
            Member member0_ 
        inner join
            Team team1_ 
                on member0_.TEAM_ID=team1_.id

 

2. Embedded type 프로젝션의 경우

- JpaMain.java

// Order 클래스에 선언되어 있는 임베디드 타입인 Address 클래스의 데이터를 가져온다.
List<Address> result_address = em.createQuery("select o.address from Order o", Address.class)
								.getResultList(); 

- Hibernate SQL

Hibernate: 
    /* select
        o.address 
    from
        
    Order o */ select 
        order0_.city as col_0_0_,
        order0_.street as col_0_1_,
        order0_.zipcode as col_0_2_ from
            ORDERS order0_ 
/* Order 클래스 내부에 선언된 Address 클래스의 데이터들만 select 해 오는 것을 확인할 수 있다. */

 

그런데 임베디드 타입은 한계가 있다.

예를 들어 JPQL 을 아래와 같이 작성할 수 없다.

- JpaMain.java

List<Address> result_address = em.createQuery("select address from Address o", Address.class)
					.getResultList();
// 이와 같이 코드를 작성할 수 없다.(오류가 발생함)

 

왜? 임베디드 타입은 어딘가에 소속되어 있는 클래스 타입으로서, 소속되어 있는 도메인 클래스를 통해 데이터 들을 가져와야 하기 때문이다.

즉, 클래스 자체적으로 데이터를 찾아올 수 없다.

 

 

3. Scala 타입 프로젝션의 경우

- JpaMain.java

// 반환 타입이 명확하지 않기 때문에 TypedQuery 형태로 코드를 작성하면 안된다.
// 즉, JPQL 코드 이후 클래스 정보를 넘겨주면 안된다.
em.createQuery("select distinct m.username, m.age from Member m")
		.getResultList(); // distince 로 중복을 제거하였다.

- Hibernate SQL

Hibernate: 
    /* select
        distinct m.username,
        m.age 
    from
        Member m */ select /* distinct 로 중복을 제거하였다. */
            distinct member0_.username as col_0_0_,
            member0_.age as col_1_0_ 
        from
            Member member0_

 

스칼라 타입 프로젝션은 일반 SQL 의 select 프로젝션과 거의 똑같다고 보면 된다.

 

그런데 고민거리가 하나 생길 수 있다.

가져와야 하는 타입이 명확하지 않을 경우는 어떻게 데이터를 가져와야 할까?

즉, 위의 코드와 같이 가져와야 하는 데이터 타입이 2개 이상일 경우라면 어떻게 해야할까?

 

다음 글에서는 프로젝션에서 여러 값을 조회하는 방법을 알아보자.

'JPA' 카테고리의 다른 글

JPQL - JPQL 기본(4)  (0) 2020.11.16
JPQL - JPQL 기본(3)  (0) 2020.11.16
JPQL - JPQL 기본(1)  (0) 2020.11.15
JPQL - JPQL 소개(2)  (0) 2020.11.13
JPQL - JPQL 소개(1)  (0) 2020.11.13