오봉이와 함께하는 개발 블로그
JPA - 객체 지향 쿼리 언어 소개 본문
728x90
객체지향 쿼리 언어 소개
JPA로 모든 것을 해결할 수 없기 때문에 약점들을 보완하기 위해서 JPA는 다양한 쿼리 방법을 지원한다.
거의 대부분은 JPQL로 해결이 가능하지만 가끔 불가능한 경우는 네이티브SQL이나 MyBatis 등을 이용하자
다양한 쿼리 방법들은 아래와 같다
- JPQL
- JPA Criteria
- QueryDSL
- 네이티브SQL
- JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용
JPQL 소개
- 가장 단순한 조회 방법이다.
- EntityManaget.find()
- 객체 그래프 탐색(a.getB().getC())
- 만약 조건이 필요해서 나이가 18살 이상인 회원을 모두 검색하고 싶다면?
JPQL
- JPA를 사용하면 엔티티 객체를 중심으로 개발한다.
- 테이블은 매핑만 하지 실질적인 개발은 엔티티를 중심으로 함.
- 문제는 검색 쿼리
- 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
- 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
- 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하다.
- 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
- JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.
- SQL과 문법이 유사하며 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN을 지원한다
- JPQL은 엔티티 객체를 대상으로 쿼리하고 SQL은 데이터베이스 테이블을 대상으로 쿼리한다.
- 결국 JPQL을 짜면 SQL로 번역되어 쿼리가 날아간다.
- SQL을 추상화해서 특정 DB SQL에 의존하지 않는다.
- JPQL을 한마디로 정의하면 객체 지향 SQL이다.
JPQL 단순한 예제
List<Member> memberList = em.createQuery(
"select m from Member m where m.name like '%kim%'",
Member.class)
.getResultList();
JPQL은 엔티티를 대상으로 쿼리하기 때문에 여기서 Member는 Member 테이블이 아니라 엔티티 Member를 가르킨다.
//검색
String jpql = "select m from Member m where m.age > 18";
List<Member> result = em.createQuery(jpql, Member.class) .getResultList();
-- 실행된 SQL
select
m.id as id,
m.age as age,
m.USERNAME as USERNAME,
m.TEAM_ID as TEAM_ID
from
Member m
where
m.age>18
Criteria 소개
JPQL은 결국 문자열이기 때문에 동적 쿼리를 구현하기 매우 까다롭고 불편하다.
그래서 Criteria가 나왔다.
문자가 아닌 자바코드로 JPQL을 작성할 수 있다. 자바 코드로 JPQL을 만들어주는 역할을 한다.
JPA의 공식 기능이지만 단점으로 너무 복잡하고 실용성이 없다.
그래서 Criteria 대신에 QueryDSL 사용을 권장한다.
Criteria 단순한 예제
//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();
QueryDSL 소개
JPQL을 잘 알면 QueryDSL을 쉽게 사용할 수 있다.
- 문자가 아닌 자바코드로 JPQL을 작성할 수 있어 JPQL을 만들어주는 역할을 한다.
- 자바 코드로 작성하기 때문에 문법 오류를 찾을 수 있다.
- 동적 쿼리 작성이 편리하다.
- 단순하고 쉽기 때문에 실무 사용을 권장한다.
QueryDSL 단순한 예제
//JPQL
//select m from Member m where m.age > 18
JPAFactoryQuery query = new JPAQueryFactory(em); QMember m = QMember.member;
List<Member> list = query.select(m)
.from(m)
.where(m.age.gt(18))
.orderBy(m.name.desc())
.fetch();
네이티브 SQL 소개
- JPA가 제공하는 SQL을 직접 사용하는 기능
- JPQL로 해결할 수 없는 특정 DB에 의존적인 기능을 사용할 수 있다.
- 오라클 CONNECT BY, 특정 DB만 사용하는 SQL 힌트
네이티브 SQL 단순한 예제
String sql =
"SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = ‘kim’";
List<Member> resultList =
em.createNativeQuery(sql, Member.class).getResultList();
실제로 직접 작성한 쿼리가 날아가게 된다.
JDBC 직접 사용, SpringJdbcTemplate 등
- JPA를 사용하며 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, MyBatis 등을 함께 사용 가능
- 단, 영속성 컨텍스트를 적절한 시점에 강제로 flush() 필요하다.
- persist()가 아니라, flush()가 되어야 DB에 데이터가 있기 때문에 적절한 시점에 강제로 플러시를 하지 않으면 원하는 결과가 나오지 않을 가능성이 다분하다.
- flush()는 commit() 시점이나 createQuery(JPQL), createNativeQuery(네이티브 SQL)가 실행될 시점에 발생한다.
- persist()가 아니라, flush()가 되어야 DB에 데이터가 있기 때문에 적절한 시점에 강제로 플러시를 하지 않으면 원하는 결과가 나오지 않을 가능성이 다분하다.
출처 : 인프런 김영한 지식공유자님의 스프링 부트와 JPA 실무 완전 정복 로드맵 강의
728x90
'BE > JPA' 카테고리의 다른 글
JPA - 프로젝션(select) (0) | 2022.06.30 |
---|---|
JPA - 기본 문법과 쿼리 API (0) | 2022.06.30 |
JPA - 실전 예제 6 - 값 타입 매핑 (0) | 2022.06.29 |
JPA - 값 타입 컬렉션 (0) | 2022.06.29 |
JPA - 값 타입의 비교 (0) | 2022.06.29 |
Comments