다형성 쿼리
예제 코드
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("B")
@PrimaryKeyJoinColumn(name = "BOOK_ID")
public class Book extends Item{
private String author;
private String isbn;
}
TYPE
엔티티의 상속 구조에서 조회 대상을 특정 자식 타입으로 한정할 때 사용한다.
JPQ
SELECT i FROM Item i
WHERE TYPE(i) IN (Book, Movie)
SQL
SELECT i FROM Item i
WHERE i.DTYPE IN ('B', 'M')
TREAT(JPA 2.1)
자바의 형변환이라고 생각하면 된다.
JPA 표준은 FROM, WHERE 절에서 사용할 수 있지만, 하이버네이트는 SELECT 절에서도 사용할 수 있다.
JPQL
SELECT i FROM Item i WHERE TREAT(i AS Book).author = 'kim'
SQL
SELECT i.* From Item i
WHERE
i.DTYPE='B'
AND i.author='kim'
사용자 정의 함수 호출(JPA 2.1)
하이버네이트 구현체를 사용하면 방언 클래스를 상속해서 구현하고 사용할 데이터베이스 함수를 미리 등록해야 한다.
public class MyH2Dialect extends H2Dialect {
public MyH2Dialect() {
// concat 함수를 add_string이란 이름에 사용자함수로 등록했다
registerFunction("add_string",
new StandardSQLFunction("concat", StandardBasicTypes.STRING));
}
}
// 프로퍼티 등록
spring.jpa.properties.hibernate.dialect=com.example.jpastudy.MyH2Dialect
// 사용
SELECT group_concat(i.name,'님') FROM Item i
Named 쿼리: 정적 쿼리
동적 쿼리
- em.createQuery("select..")처럼 JPQL을 문자로 완성해서 직접 넘기는 것을 동적 쿼리라 한다. 런타임에 특정 조건에 따라 JPQL을 동적으로 구성할 수 있다.
정적 쿼리
- 미리 정의한 쿼리에 이름을 부여해서 필요할 때 사용할 수 있는데 이것을 Named 쿼리라 한다. Named 쿼리는 한 번 정의하면 변경할 수 없는 정적인 쿼리다.
- 애플리케이션 로딩 시점에 JPQL 문법을 체크하고 미리 파싱 해준다. 따라서 오류를 빨리 확인할 수 있고, 사용하는 시점에는 파싱 된 결과를 재사용하므로 성능상 이점도 있다.
- 변하지 않는 정적 SQL이 생성되므로 조회 성능 최적화에도 도움이 된다.
- Spring Data JPQ의 @Query를 사용하는 것을 권장한다.
@Entity
@NamedQueries({
@NamedQuery(
name = "Member.findByUsername",
query = "SELECT m FROM Member m WHERE m.username = :username")})
public class Member {
@Id
private Long id;
private String username;
}
// 사용
List<Member> resultList = em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username","회원1")
.getResultList();
728x90