[자바 ORM 표준 JPA 프로그래밍 - 기본편] 11-4강~7강


https://inf.run/2zDo 강의를 수강하고 작성하는 게시물입니다.


1. 다형성 쿼리

1.1. TYPE

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

아래는 Item 중에 Book, Movie를 조회하는 쿼리이다.

-- jpql
select i from Item i
where type(i) IN (Book, Movie)
-- sql
select i from i
where i.DTYPE in ('B', 'M')

1.2. TREAT

JPA 2.1 이상에서 사용가능하다.

자바의 타입 캐스팅과 유사하다.

상속 구조에서 부모 타입을 특정 자식 타입으로 다룰 때 사용한다.

FROM, WHERE, SELECT 중에서 사용할 수 있다.

아래는 부모인 Item과 자식 Book일 경우 사용 예시이다.

[JPQL]

select i from Item i
where treat(i as Book).auther = 'kim'

[SQL]

select i.* from Item i
where i.DTYPE = 'B' and i.auther = 'kim'

위처럼 다운 캐스팅 처럼 쓸 수 있다.

2. 엔티티 직접 사용

2.1. 기본 키 값

JPQL에서 엔티티를 직접 사용하면 SQL에서 해당 엔티티의 기본키 값을 사용한다.

[JPQL]

select count(m.id) from Member m
-- 엔티티의 아이디를 사용
select count(m) from Member m
-- 엔티티를 직접 사용

SQL

select count(m.id) as cnt from Member m

기본키 값을 이용하는 방법은 아래 두 방법이 있다.

2.1.1. 엔티티를 파라미터로 전달

String jpql = select m from Member m where m = :member; 
List resultList = em.createQuery(jpql)
    .setParameter("member", member) 
    .getResultList();

2.1.2. 식별자를 직접 전달

String jpql = select m from Member m where m.id = :memberId; 
List resultList = em.createQuery(jpql)
    .setParameter("memberId", memberId) 
    .getResultList();

2.1.3. 두 예시의 실행결과

두 방법 모두 실행된 SQL이 아래와 같다.

select m.* from Member m where m.id=?

실행된 SQL이 같은 이유는 엔티티가 DB로 넘어가면 구분하는 과정이 PK이므로 같을 수 밖에 없다.

2.2. 외래 키 값

Team team = em.find(Team.class, 1L);
String qlString = select m from Member m where m.team = :team; 
List resultList = em.createQuery(qlString)
    .setParameter("team", team) 
    .getResultList();
String qlString = select m from Member m where m.team.id = :teamId;
List resultList = em.createQuery(qlString)
    .setParameter("teamId", teamId)
    .getResultList();

3. Named 쿼리

미리 엔티티에 쿼리이름을 부여하여 사용할 수 있다.

@Entity
@NamedQuery(
    name = "Member.findByUsername",
    query="select m from Member m where m.username = :username")
public class Member {
    ...
}
List<Member> resultList =
em.createNamedQuery("Member.findByUsername", Member.class)
    .setParameter("username", "회원1")
    .getResultList();

위와 같이 사용하면 어떤 메리트가 있을까?

  • 미리 정의해서 이름을 부여해두고 사용하는 JPQL
  • 정적쿼리(동적 불가)
  • 어노테이션, XML에 정의
  • 애플리케이션 로딩 시점에 초기화 후 재사용
  • 애플리케이션 로딩 시점에 쿼리를 검증

정적쿼리라 변하지 않는데 JPA나 Hibernate같은 애들이 SQL로 파싱을 하고 캐시에 저장한다.

애플리케이션 로딩 시점에 쿼리를 검증하는 기능이 가장 막강하다. 쿼리를 잘못 쓸 경우 쿼리가 잘못되었다는 오류가 발생한다.

Spring data JPA에서 Repository에 쿼리문을 어노테이션으로 쓸 수 있는데 자동으로 Named 쿼리로 등록을 해준다.

강사님은 개인적으로 Named 쿼리를 쓰는건 비추천하고 결국 실무에서는 Spring data JPA를 사용하게 될거라고 말하셨다.

댓글 남기기