JPQL
JPQL은 엔티티 객체를 조회하는 객체지향 쿼리다.
JPQL은 SQL을 추상화해서 특정 데이터베이스에 의존하지 않으며, SQL에 비해 간결하다.
@Entity(name="MEMBER")
public class Member{
@Column(name="name")
private String username;
}
//사용
String jpql = "select m from Member as m where m.username = "kim"
List<Member> resultList =
em.createQuery(jpql, Member.class).getResultList();
작성한 JPQL을 실행하려면 쿼리 객체를 만들어야 한다. 쿼리 객체는
TypeQuery와 Query가 있는데 반환할 타입을 명확하게 지정할 수 있으면 TypeQuery객체를 사용하고 명확하게 지정할 수 없으면 Query 객체를 사용하면 된다.
//Type Query사용
TypeQuery<Member> query = em.createQuery("SELECT m FROM Member m", Member.class);
for(Member member : resultList)({
System.out.println("member = " + member);
})
// Query사용
Query query = em.createQuery("SELECT m.username, m.age from Member m");
for(Object o : resultList)({
Object[] result = (Object[]) o; //결과가 둘 이상이면 Object[]반환
})
SELECT 절에서 여러 엔티티나 컬럼을 선택할 때는 반환할 타입이 명확하지 않으므로 Query 객체를 사용해야 한다.
결과조회
- query.getResultList() : 결과를 예제로 반환한다. 만약 결과가 없으면
빈 컬렉션을 반환한다. - query.getStringResult(): 결과가 정확히 하나일 때 사용한다.-결과가 1개보다 많으면 NonUniqueResultException예외가 발생
- -결과가 없으면 NoResultException 예외가 발생한다.
파라미터 바인딩
-이름 기준 파라미터:
String usernameParam = "User1";
TypeQuery<Member> query = em.createQuery("SELECT m FROM Member m where m.username = :username",Member.class);
query.setParameter("username", usernameParam);
List<Member> resultList = query.getResultList();
-위치 기준 파라미터
List<Member> members =
em.createQuery("SELECT m FROm Member m where m.username =?1", Member.class)
.setParameter(1, usernameParam)
.getResultList();
프로젝션
SELECT 절에 조회할 대상을 지정하는 것을 프로젝션이라 한다.
프로젝션 대상은 엔티티, 엠비디드타입, 스칼라 타입이 있다.
-임베디드 타입 프로젝션
임베디드 타입은 조회의 시작점이 될 수 없다는 제약이 있다.
String query = "SELECT o.address FROM Order o ";
List<Address> addresses = em.createQuery(query,Address.class).getResultList();
임베디드 타입은 엔티티 타입이 아닌 값 타입이다. 따라서 이렇게 직접 조회한 임베디드 타입은 영속성 컨텍스트에서 관리되지 않는다.
-스칼라 타입 프로젝션
숫자, 문자 날짜와 같은 기본 데이터 타입들을 스칼라 타입이라 한다.
List<String> usernames = em.createQuery("select username FROM Member m ", String.class).getResultList();
중복 데이터를 제거하려면 DISTINCT를 사용한다.
-여러 값 조회
꼭 필요한 데이터들만 선택해서 조회할때 사용한다. 프로젝션에 여러 값을 선택하면 TypeQuery를 사용할 수 없고 대신에 Query를 사용해야 한다.
Query query = em.createQuery("SELECT m.username, m.age FROM Member m ");
List resultList = query.getResultList();
Iterator iterator = resultList.iterator();
while(iterator.hasNext()){
Object[] row = (Object[]) iterator.next();
String username = (String) row[0];
Integer age = (Integer) row[1];
}
List<Object[]> resultList =
Qem.createQuery("SELECT m.username, m.age FROM Member m ");
List resultList = query.getResultList();
Iterator iterator = resultList.iterator();
while(iterator.hasNext()){
Object[] row = (Object[]) iterator.next();
String username = (String) row[0];
Integer age = (Integer) row[1];
}
-NEW 명령어
- 패키지 명을 포함한 전체 클래스 명을 입력해야 한다.
- 순서와 타입이 일치하는 생성자가 필요하다.
TypedQuery<UserDTO> query = em.createQuery("SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m", UserDTO.class);
List<UserDTO> resultList = query.getResultList();
List<UserDTO> resultList = query.getResultList();
페이징 API
- setFirstResult(int startPosition): 조회 시작 위치(0부터 시작한다)
- setMaxResults(int maxResult): 조회할 데이터 수
TypeQuery<Member> query = em.createQuery("SELECT m FROM Member m ORDER BY m.username DESC"), Member.class);
query.setFirstResult(10);
query.setMaxResult(20);
query.getResultList();
-페치 조인
페치 조인은 JPQL에서 성능 최적화를 위해 제공하는 기능이다.
이것은 연관된 엔티티나 컬렉션을 한 번에 같이 조회하는 기능인데
join fetch 명령어로 사용할 수 있다.
엔티티 페치 조인
String jpql = "select m from Member m join fetch m.team"
List<Member> members = em.createQuery(jpql, Member.class).getResultList();
for(Member member : members){
//패치 조인으로 회원과 팀을 함께 조회하기 때문에 지연 로딩 발생안함
System.out.println(member.getUsername()+"teamname = "+member.getTeam().name());
}
Criteria쿼리
JPQL을 생성하는 빌더 클래스다. Criteria의 장점은 문자가 아닌
query.select(m).where(...)처럼 프로그래밍 코드로 JPQL을 작성할 수 있다는 점이다.
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> result = em.createQuery(cq).getResultList();
Criteria쿼리 생성 방법
- Criteria쿼리를 생성하려면 먼저 Criteria 빌더를 얻어야 한다. Criteria빌더는 EntityManager나
EntityManagerFactory에서 얻을 수 있다.CriteriaBuilder cb = em.getCriteriaBuilder();
- Criteria 쿼리 빌더에서 Criteria쿼리를 생성한다. 이떄 반환 타입을 지정할 수 있다.
CriteriaQuery<Member> cq = cb.createQuery(Member.class)
- From 절을 생성한다. 반환된 값 m은 Criteria에서 사용하는 특별한 별칭이다. m을 조회의 시작점
이라는 의미로 쿼리 루트라 한다.Root<Member> m = cq.from(Member.class)
- SELECT 절을 생성한다.
cq.select(m);
조건절 생성 방법
Predicate usernameEqual = cb.equal(m.get("username"),"회원1")
Order ageDesc = cb.desc(m.get("age"))
cq.select(m).where(usernameEqual).orderBy(ageDesc)
em.createQuery(cq).getResultList();
튜플
Criteria는 Map과 비슷한 튜플이라는 특별한 반환 객체를 제공한다.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Member> m = cq.from(Member.class);
cq.multiselect(m.get("username").alias("username"),
m.get("age").alias("age")
);
TypedQuery<Tuple> query = em.createQuery(cq);
List<Tuple> resultList = query.getResultList();
for (Tuple tuple : resultList) {
String username = tuple.get("username", String.class);
Integer age = tuple.get("age",Integer.class);
}
QueryDSL
QueryDSL도 Criteria처럼 JPQL 빌더 역할을 한다. QueryDSL의 장점은 코드 기반이면서 단순하고 사용하기 쉽다.
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
JPAQuery query = new JPAQuery(em);
QMember qMember = new QMember("m");
List<Member> members = query.from(qMember)
.where(qMember.name.eq("회원1"))
.orderBy(qMember.name.desc())
.list(qMember);
조인
QJoinParent joinParent = QJoinParent.joinParent;
QJoinChild joinChild = QJoinChild.joinChild;
List<JoinParent> list = query.from(joinParent).leftJoin(joinParent.joinChild, joinChild)
.fetch().on(joinChild.isNotNull()).list(joinParent);
조인의 기본 문법은 첫 번째 파라미터에 조인 대상을 지정하고, 두 번째 파라미터에 별칭으로 사용할 쿼리 타입을 지정하면 된다.
→join(조인대상, 별칭으로 사용할 쿼리 타입)
네이티브 SQL
SQL을 직접 사용할 수 있는 기능으로 SQL은 지원하지만 JPQL이 지원하지 않는 기능이 있을때 네이티브 SQL을 사용한다.
네이티브 쿼리 API는 다음3가지가 있다.
//결과 타입 정의
public Query createnativeQuery(String sqlString, Class resultClass)
//결과 타입을 정의할 수 없을 때
public Query createnativeQuery(String sqlString)
//결과 매핑 사용
public Query createnativeQuery(String sqlString, String resultSetMapping)
엔티티 조회
네이티브 SQL은 em.createNativeQuery(SQL, 결과 클래스)를 사용한다.
첫번째 파라미터는 네이티브 SQL을 입력, 두번째 파라미터는 조회할
엔티티의 타입을 입력한다.
'SPRING > JPA' 카테고리의 다른 글
[JPA]JPA,Hibernate, Spring Data JPA차이 (0) | 2022.02.09 |
---|---|
[JPA] 연관관계 (0) | 2022.02.09 |
[JPA]스프링 데이터 Common:커스텀 리포지토리 (0) | 2022.01.21 |
[JPA]MappedSuperClass (0) | 2022.01.21 |
[JPA] 프록시 (0) | 2022.01.21 |