JPA는 복잡한 검색 조건을 사용해서 엔티티 객체를 조회하는 다양한 쿼리 기술을 지원한다.
💡 JPA가 지원하는 다양한 쿼리 방법
- JPQL: 표준 문법
- JPA Criteria, QueryDSL: 문자가 아닌 프로그래밍 코드로 JPQL 작성
- 네이티브 SQL: 표준 SQL 문법을 벗어나는 쿼리를 작성할 수 있는 기능 제공
- JDBC API 직접 사용, MyBatis와 같은 SQL 매퍼 프레임워크 사용
엔티티 객체를 조회하는 객체지향 쿼리
EntityManager.find()
a.getB().getC()
)JPQL
이라는 객체 지향 쿼리 언어를 제공한다.List<Member> result = em.createQuery(
"select m From Member m where m.name like '%hello%'",
Member.class
).getResultList();
Member
는 테이블이 아니라 엔티티이다.실행된 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
문자가 아닌 자바코드로 JPQL을 작성할 수 있다.
//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()
문자가 아닌 자바코드로 JPQL을 작성할 수 있으며,
실용성이 없는 Criteria 대신 오픈 소스 라이브러리인 QueryDSL을 사용한다!
String
문자가 아닌 자바 코드로 작성하기 때문에 컴파일 시점에 문법 오류를 찾을 수 있다.//JPQL
//select m from Member m where m.age > 18
JPAFactoryQuery queryFactory= new JPAQueryFactory(em);
QMember m = QMember.member;
List<Member> list = queryFactory.selectFrom(m)
.where(m.age.gt(18))
.orderBy(m.name.desc())
.fetch()
QMember
는 Member
엔티티 클래스를 기반으로 생성한 QueryDSL
쿼리 전용 클래스→ Criteria
코드와 비교하면 훨씬 직관적!
JPA가 제공하는 SQL을 직접 사용하는 기능
CONNECT BY
, 특정 DB만 사용하는 SQL 힌트String sql = "SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = 'kim'";
List<Member> resultList = em.createNativeQuery(sql, Member.class).getResultList();
JPA를 사용하면서
JDBC 커넥션
을 직접 사용하거나,
SpringJdbcTemplate
,MyBatis
등을 함께 사용할 수 있다.
String sql = "SELECT ID, AGE, TEAM_ID, NAME FROM MEMBER WHERE NAME = 'kim'";
List<Member> resultList = em.createNativeQuery(sql, Member.class).getResultList();
API
]select m from Membebr as m where m.age > 18
Member
는 테이블이 아닌 엔티티 Member
, age
) JPQL
키워드는 대소문자 구분 ❌ (SELECT
, FROM
, where
) m
) (as
는 생략 가능)//TypeQuery
TypedQuery<Member> query = em.createQuery("select m from Member m", Member.class);
TypedQuery<String> query1 = em.createQuery("select m.username from Member m", String.class);
//Query
Query query2 = em.createQuery("select m.username, m.age from Member m");
TypeQuery
: 반환 타입이 명확할 때 사용Query
: 반환 타입이 명확하지 않을 때 사용다음 메서드들을 호출하면 실제 쿼리를 실행해서 데이터베이스를 조회한다.
query.getResultList()
: 결과가 하나 이상일 때, 리스트 반환query.getSingleResult()
: 결과가 정확히 하나일 때, 단일 객체 반환javax.persistence.NoResultException
javax.persistence.NonUniqueResultException
:
를 사용한다.SELECT m FROM Member m where m.username = :username
query.setParameter("username", usernameParam);
?
다음에 위치 값을 주면 된다. (위치 값은 1
부터 시작)SELECT m FROM Member m where m.username = ?1
query.setParameter(1, usernameParam)