10.1 객체지향 쿼리 소개
ORM을 사용하면 데이터베이스 테이블이 아닌 엔티티 객체를 대상으로 개발.
검색도 테이블이 아닌 엔티티 객체를 대상으로 하는 방법이 필요.
종류 | 설명 |
---|---|
SQL | 데이타베이스 테이블을 대상으로 하는 데이터 중심의 쿼리 |
JPQL | 엔티티 객체를 대상으로 하는 객체지향 쿼리. |
◉ JPQL
JPA는 JPQL을 사용하면 이를 분석하여 SQL을 만들어 데이터베이스를 조회.
이 조회한 결과로 엔티티 객체를 생성해서 반환.
◉ JPA가 공식 지원하는 기능
객체지향 쿼리 | 설명 |
---|---|
JPQL | Java Persistence Query Language |
Criteria 쿼리 | JPQL을 편하게 작성하도록 도와주는 API, 빌더 클래스 모음 |
네이티브 SQL | JPA에서 JPQL 대신 직접 SQL을 사용 |
◉ 다른 객체지향 쿼리
객체지향 쿼리 | 설명 |
---|---|
QueryDSL | JPQL을 편하게 작성하도록 도와주는 빌더 클래스 모음. 비표준 오픈소스 프레임워크 |
JDBC 직접 사용, MyBatis 등등 | 직접 사용 가능 |
10.1.1 JPQL 소개
JPQL(Java Persistence Query Language)
은 엔티티 객체를 조회하는 객체지향 쿼리다.
JPQL은 SQL을 추상화해서 특정 데이트베이스에 의존하지 않는다.
JPQL은 SQL보다 간결하다.
회원 엔티티
@Entity(name = "Member")
public class Member {
@Column(name = "name")
private String username;
// ...
}
JPQL 사용 예
// 쿼리 생성
String jpql = "select m from Member as m where m.username = 'kim'";
List<Member> resultList =
em.createQuery(jpql, Member.class).getResultList();
실행된 SQL
select
member.id as id,
member.age as age,
member.team_id as team,
member.name as name
from
Member mbmer
where
member.name = 'kim'
10.1.2 Criteria 쿼리 소개
Criteria는 JPQL을 생성하는 빌더 클래스.
JPA 2.0부터 Criteria 지원.
장점
- 컴파일 시점에 오류를 발견할 수 있다.
- IDE를 사용하면 코드 자동완성을 지원한다.
- 동적 쿼리를 작성하기 편하다.
Criteria 쿼리 예
// Criteria 사용 준비
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> query = cb.creatQuery(Member.class);
//루크 클래스(조회를 시작할 클래스)
Root<Member> m = query.from(Member.class);
//쿼리 생성
CriteriaQuery<Member> cq =
query.select(m).where(cb.equal(m.get("username"), "kim));
List<Member> resultList = em.createQuery(cq).getResultList();
메타모델 API
Member 엔티티 클래스로부터 Member_라는 Criteria 전용 클래스를 생성. -> 메타모델.
메타모델 사용 전 | 사용 후 |
---|---|
m.get("username") | m.get(Member_.username) |
단점
- 모든 장점을 상쇄할 정도로 복잡하고 장황하다.
- 사용하기 불편하다.
- 코드를 읽기 어렵다.
QueryDSL 소개
QueryDSL도 Criteria처럼 JPQL 빌더 역할을 한다.
JPA 표준은 아님
QueryDSL 장점
- 단순하고 사용하기 쉽다.
- 스프링 데이터 프로젝트에서 지원.
QueryDSL 코드
//준비
JPAQuery query = new JPAQuery(em);
QMember member = QMember.member;
//쿼리, 결과조회
List<Member> members =
query.from(member)
.where(member.username.eq("kim"))
.list(member);
QueryDSL도 쿼리 전용 클래스를 만들어야 한다. QMember는 Member 엔티티 클래스를 기반으로 생성한 QueryDSL 쿼리 전용 클래스.
10.1.4 네이티브 SQL 소개
JPA는 SQL을 직접 사용할 수 있는 기능을 지원. -> 네이티브 SQL
네이티브 SQL 단점
특정 데이터베이스에 의존하는 SQL 작성
데이터베이스를 변경하면 네이티브 SQL도 수정.
네이티브 SQL 코드
직접 작성한 SQL을 데이터베이스에 전달.
String sql = "SELECT ID, AGE, ITEM_ID, NAME FROM MEMBER WHERE NAME = 'kim'";
List<Member> resultList =
em.createNativeQuery(sql, Member.class).getResultList();
10.1.5 JDBC직접 사용, MyBatis 같은 SQL 매퍼 프레임워크 사용
JPA는 JDBC 커넥션을 얻는 API를 제공하지 않음.
JPA 구현체가 제공하는 방법을 사용해야 함.
하이버네이트 JDBC 획득
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLExcetion {
// work ...
}
});
- JPA를 우회해서 데이터베이스에 접근.
- JPA가 전혀 인식하지 못함.
- JDBC나 마이바티스를 JPA와 함께 사용하려면 영속성 컨텍스트를 적절한 시점에 강제로 플러시 해야 함.
- SQL을 실행하기 직전에 영속성 컨텍스트를 수동으로 플러시 해야 함.