(JPA)JPA의 다양한 쿼리 사용 방법
JPA의 다양한 쿼리 사용 방법
JPQL
- JPA 를 사용하게 되면 Entity 객체를 중심으로 개발하게 되는데, 검색 쿼리를 어떻게 처리해야할까?
- 검색을 할 때도 테이블이 아닌 Entity 객체를 대상으로 검색해야 한다.
- 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능에 가깝다.
- 애플리케이션이 필요한 데이터만 DB 에서 불러오려면 결국 검색 조건이 포함된 SQL 이 필요하다.
JPA 는 SQL 을 추상화한 JPQL 이라는 객체 지향 쿼리 언어를 제공한다.
- SQL과 문법이 유사하며, ANSI SQL 에서 지원하는 모든것을 사용할 수 있다.
- SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 등등
JPQL 은 Entity 객체를 대상으로 쿼리
SQL 은 DB 테이블을 대상으로 쿼리
- JPQL 을 작성하면, SQL 로 변역되어 동작하게 된다.
1
2
3
String jpql = "select m from Member m where m.name like '%hello%'";
List<Member> result = em.createQuery(jpql, Member.class).getResultList();
- JPQL 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Hibernate:
/*
select
m
from
Member m
where
m.name like '%hello%'
*/
member0_.member_id,
member0_.city,
member0_.street,
member0_.zipcode,
member0_.name,
from
Member member0_
where
member0_.name like '%hello%'
- JPQL 이 번역되어 발생한 SQL
- 위에 주석 처리를 통해 작성된 JPQL 을 보여주고, 아래에 실제 발생된 SQL 을 보여준다.
- 테이블이 아닌 객체를 대상으로 검색하는 객체지향 쿼리이다.
- SQL 을 추상화해서, 특정 데이터베이스 SQL 에 의존적이지 않다.
Criteria
동적 쿼리를 활용하기 어려운 JPQL 의 단점을 보완할때 사용.
동적 쿼리를 활용할때 뿐만 아니라 다른 여러 기능을 활용할 수 있게 해준다.
1
2
3
4
5
6
7
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> = cb.createQuery(Member.class);
Root<Member> m = query.from(Member.class);
CriteriaQuery<Member> cq = query.select(m).where(cb.equal(m.get("name"), "kim"));
List<Member> result = em.createQuery(cq).getResultList();
- 단순 사용 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> query = cb.createQuery(Member.class);
Root<Member> m = query.from(Member.class);
CriteriaQuery<Member> cq = query.select(m);
String name = "hello";
if (name != null) {
cq = cq.where(cb.equal(m.get(name), "kim"));
}
List<Member> result = em.createQuery(cq).getResultList();
- 동적 쿼리 작성 예제
Criteria 정리
- 문자(String)가 아닌 자바 코드로 JPQL 을 작성 할 수 있다.
- JPQL 빌더 역할
- JPA 공식 기능
- JPQL 에 비해 단순하지만, SQL 보다 직관적이지 않아 유지 보수 측면에서 매우 좋지 않다.(실무에서 활용하기에는 무리가 있다.)
- Criteria 대신 QueryDSL 사용을 권장한다.
QueryDSL
JPQL 을 좀 더 쉽게 활용하기 위해 사용하는 오픈소스 라이브러리
JPQL 빌더 역할
사용하기 전에 추가적인 설정이 필요하지만, 사용하기에는 매우 편리하다.
컴파일 시점에 문법 오류를 찾을 수 있다.
단순하고 쉽다.(실무에서 활용하기 좋다.)
1
2
3
4
5
6
7
8
9
JPAFactoryQuery query = new JPAQueryFactory(em);
QMember m = QMember.member;
List<Member> list =
query
.selectFrom(m)
.where(m.age.gt(18))
.orderBy(m.name.desc())
.fetch();
- 단순 사용 예제
네이티브 SQL
JPA 가 제공하는 SQL 을 직접 사용하는 기능
JPQL 로 해결할 수 없는 특정 데이터베이스에 의존적인 기능
- 오라클 DB 의 CONNECT BY 등 특정 DB 만 사용하는 SQL 힌트
1
2
em.createNativeQuery("select member_id, city, street, zipcode, username from Member")
.getResultList();
- 단순 사용 예제
1
2
3
4
5
6
7
8
9
10
Hibernate:
/* dynamic native SQL query */
select
member_id,
city,
street,
zipcode,
username
from
Member
- 작성한 NativeQuery 그대로 적용되는것을 볼 수 있다.
JDBC 직접 사용
- 네이티브 SQL 을 사용하기 보다 JDBC 를 직접 사용하는게 좋다.
- JPA 를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, 마이바티스 등을 함께 사용할 수 있다.
- 주의할 점은 영속성 컨텍스트를 적절한 시점에 강제로 flush 해줘야 한다.
- JPA 를 우회해서 SQL 을 실행하기 직전에 영속성 컨텍스트를 수동 flush 해줘야 한다.
- flush 가 동작하는 시기: commit 되기 직전 그리고 query 가 발생 했을때
1
2
3
4
5
6
7
8
9
10
Member member = new Member();
member.setName("member1");
em.persist(member);
// Select Query가 발생하여, 자동으로 flush를 해준다.
List<Member> result = em.createNativeQuery(sql).getResultList();
for (Member m : result) {
System.out.println("member = " + m);
}
- JPA 기술을 사용할때는 자동으로 flush 해줘서 문제가 없다.
1
2
3
4
5
6
Member member = new Member();
member.setName("member1");
em.persist(member);
// em.flush(); 강제로 flush()
// dbconn.executeQuery("select * from member");
JDBC 는 JPA 와 관련이 없기 때문에, 자동이로 flush 를 해주지 않는다.
SQL 이 실행되기 전에 강제로 flush 를 꼭 해줘야 한다.
REFERENCE
#JPA_다양한_쿼리_사용_방법
This post is licensed under CC BY 4.0 by the author.