1. 객체지향 쿼리
- JPA에서 엔티티를 조회하는 방법?
- EntityManager.find() 메소드
- 조건부 탐색을 하고싶을 땐? (e.g. 나이가 18세 이상인 회원을 조회)
- 모든 엔티티를 조회 후에 조건을 적용해야 함
- 데이터베이스 조회 시 필요한 내용을 최대한 거를 필요가 있음
- JPQL(Java Persistence Query Language)
- 테이블이 아닌 객체를 대상으로 검색하는 객체지향 쿼리
- SQL을 추상화 해서 특정 데이터베이스 SQL에 의존하지 않음
- Criteria 쿼리
- JPQL을 편하게 작성하도록 도와주는 API, 빌더 클래스 모음
- 네이티브 SQL
- JPA에서 JPQL대신 직접 SQL을 사용할 수 있도록 해줌
- QueryDSL
- Criteria 쿼리처럼 JPQL을 편하게 작성하도록 도와주는 빌더 클래스 모음
- 비표준 오픈소스 프레임워크
- JDBC 직접 사용
- MyBatis와 같은 SQL 매퍼 프레임워크를 사용
1. JPQL
- 엔티티 객체를 조회하는 객체지향 쿼리
- SQL과 비슷한 문법, ANSI 표준 SQL이 제공하는 기능을 유사하게 지원
- SQL보다 간결한 문법
- SQL을 추상화 했기 때문에 특정 데이터베이스에 의존하지 않음
- 데이터베이스 방언(Dialect)만 변경하면 JPQL을 수정하지 않아도 데이터베이스 변경 가능
String jpql = "select m from Member as m where m.username = 'kim'";
List<Member> result = em.createQuery(jpql, Member.class).getResultList();
/*
SELECT
member.id as id,
member.age as age,
member.team_id as team,
member.name as name,
FROM
MEMBER member
WHERE
member.name = "kim"
*/
- m.username과 같이 데이터베이스 컬럼명이 아닌 엔티티의 필드명으로 조회
2. Criteria 쿼리
- JPQL을 생성하는 빌더 클래스
- 문자가 아닌 프로그래밍 코드(함수 호출)로 JPQL 작성이 가능함
- e.g. query.select(m).where(…)
- 이게 왜 장점이냐?
- JPQL을 직접 작성할 경우 쿼리문에 오타가 있어도 런타임 시점에 오류가 발생함(문자기반 쿼리의 단점)
- 장점
- 컴파일 시점에 오류 발견이 가능
- IDE를 사용하면 코드 자동완성을 지원
- 동적 쿼리를 작성하기 편함
- 단점
//String jpql = "select m from Member as m where m.username = 'kim'";
//Criteria 사용 준비
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> query = cb.createQuery(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();
- Critera 대신 QueryDSL 사용을 권장
3. QueryDSL
- Criteria와 마찬가지로 JPQL 쿼리 빌더 역할
- 코드 기반이면서 단순하고 사용이 쉬움
- 실무에서 사용 권장
//준비
JPAQuery query = new JPAQuery(em);
QMember member = QMember.member;
//쿼리, 결과 조회
List<Member> members =
query.from(member).where(member.username.eq("kim")).list(member);
- 어노테이션 프로세서를 사용해서 쿼리 전용 클래스(QMember)를 만들어야 함
4. 네이티브 SQL
- SQL을 직접 사용
- JPA가 해결할 수 없는 특정 데이터베이스에 의존적인 문법을 사용해야 할 때
- e.g. 오라클(CONNECTED BY), 특정 데이터베이스에서만 동작하는 SQL 힌트
- 데이터베이스를 변경할 경우 쿼리도 수정해야 함
String sql = "SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = 'kim'";
List<Member> resultList =
em.createNativeQuery(sql, Member.class).getResultList();
5. JDBC 직접 사용, Mybatis와 같은 SQL 매퍼 프레임워크 사용
- JDBC를 직접 사용하고 싶을 때?
- JPA는 JDBC 커넥션을 획득하는 API를 제공하지 않음
- JPA 구현체에서 제공하는 방법을 사용해야 함
//하이버네이트에서 JDBC 커넥션 획득
Session session = em.unwrap(Session.class);
session.doWork(new Work(){
@Override
public void execute(Connection connection) throws SQLException {
// work..
}
});
- JDBC를 직접 사용하거나 Mybatis를 사용하는거 모두 JPA를 우회해서 데이터베이스를 접근하는 것
- JPA의 영속성 컨텍스트와 데이터베이스가 불일치 상태가 될 수 있음
- 따라서 SQL 실행 전 반드시 flush()를 통해 영속성 컨텍스트를 데이터베이스와 동기화 해야 함
- 스프링 프레임워크에서는 JPA와 Mybatis를 쉽게 통합이 가능함
- 스프링 프레임워크의 AOP를 활용해서 JPA를 우회하여 데이터베이스에 접근하는 메소드를 호출할 때마다 영속성 컨텍스트를 플러시 해주면 됨