슬기로운 개발생활

[JPA] JPQL(Java Persistence Query Language)이란?

by coco3o
반응형

JPA는 복잡한 조건을 사용해서 엔티티 객체를 조회할 수 있는 다양한 쿼리 기술을 지원한다.

 

이번 글에서는 다양한 객체지향 쿼리 중 JPQL에 대해 알아보도록 하자.

 

참고


JPQL(Java Persistence Query Language)

JPQL은 엔티티 객체를 조회하는 객체지향 쿼리다.

 

테이블을 대상으로 쿼리하는 것이 아니라 엔티티 객체를 대상으로 쿼리한다.

 

SQL과 비슷한 문법을 가지며, JPQL은 결국 SQL로 변환된다.

 

JPA에서 제공하는 메소드 호출만으로 섬세한 쿼리 작성이 어렵다는 문제에서 JPQL이 탄생된 것이다.

 

JPQL 특징

  • 테이블이 아닌 객체를 검색하는 객체지향 쿼리
  • SQL을 추상화 했기 때문에 특정 벤더에 종속적이지 않음
  • JPA는 JPQL을 분석하여 SQL을 생성한 후 DB에서 조회

기본 문법

String jpql = "select m from Member as m where m.name = 'coco'";

JPQL은 SQL과 문법이 유사하지만 몇 가지 다른 점이 있다.

 

1. 대소문자 구분

엔티티와 속성은 대소문자를 구분한다.

엔티티 이름인 Member, 그리고 Member의 속성 name은 대소문자를 구분해줘야 한다.

반면에 SELECT, FROM, AS 같은 JPQL 키워드는 대소문자를 구분하지 않아도 된다.

 

2. 엔티티 이름

JPQL에서 사용한 Member는 클래스 이름이 아닌 엔티티 이름이다. 엔티티 이름은 @Entity(name="abcd")로 설정 가능하다.

name 속성을 생략하면 기본 값으로 클래스 이름을 사용한다.

 

3. 별칭

JPQL에서 엔티티의 별칭은 필수적으로 명시해야 한다.

별칭을 명시하는 AS 키워드는 생략할 수 있다.


TypedQuery, Query

JPQL을 실행하려면 쿼리 객체를 만들어야 한다. 쿼리 객체로는 TypedQuery와 Query가 있는데

반환할 타입을 명확하게 지정할 수 있으면 TypedQuery 객체를, 명확하게 지정할 수 없으면 Query 객체를 사용한다.

 

TypedQuery

public static void typedQuery(EntityManager em) {
    String jpql = "select m from Member m";
	TypedQuery<Member> query = em.createQuery(jpql, Member.class);
	
	List<Member> list = query.getResultList();
	for( Member member : list) {
		System.out.println("Member : " + member);
	}
}

EntityManager 객체에서 createQuery() 메소드를 호출하면 쿼리가 생성된다.

em.createQuery 메소드를 호출할 때 두 번째 인자로 엔티티 클래스를 넘겨준다.

 

Query

public static void Query(EntityManager em) {
    String jpql = "select m.name, m.age from Member m";
	Query query = em.createQuery(jpql);
	
	List<Object> list = query.getResultList();
	
    for( Object object : list ) {
	      Object[] results = (Object[]) object;
	      
	      for( Object result : results ) {
	          System.out.print ( result );
	     }
	     System.out.println();
	  }
}

Query 타입은 데이터 검색 결과의 타입을 명시하지 않는다.


파라미터 바인딩

파라미터 바인딩에는 이름 기준 파라미터와 위치 기준 파라미터가 있다.

위치 기준 파라미터 보다 이름 기준 파라미터가 더 명확하다.

 

이름 기준 파라미터

public static void namedParameter(EntityManager em, String param) {
    String jpql = "select m from Member m where m.name = :name";
	TypedQuery<Member> query = em.createQuery(jpql, Book.class);
	query.setParameter("name", param);
	
	List<Member> list = query.getResultList();
}

이름을 기준으로 파라미터를 바인딩 한다. 콜론( : ) 을 사용해 데이터가 추가될 곳을 지정하고,

query.setParameter() 메소드를 호출해 데이터를 동적으로 바인딩 한다.

 

위치 기준 파라미터

public static void locationalParameter(EntityManager em, String param) {
    String jpql = "select m from Member m where m.name = ?1";
    List<Member> members = em.createQuery(jpql, Member.class)
    .setParameter(1, param)
    .getResultList();
}

위치 기준 파라미터를 사용하려면 ? 다음에 위치 값을 주면 된다. 위치 값은 1부터 시작한다.

위의 예시처럼 메소드 체이닝 방식으로 작성할 수도 있다.


DTO 사용시 - new 명령어

엔티티를 대상으로 조회하면 편리하겠지만, 꼭 필요한 데이터들만 선택해서 조회해야 할 때도 있다.

이럴때 MemberDto처럼 의미 있는 객체로 변환해서 사용한다.

@AllArgsConstructor
@NoArgsConstructor
@Getter @Setter
public class MemberDto {
	private String name;
	private int age;
}

코드를 간단하게 하기 위해 lombok을 사용했다.

public static void useDto (EntityManager em) { // Dto 사용 ( new 명령어 )
	String jpql = "select new com.coco.example.MemberDto(m.name, m.age) from Member m";
	TypedQuery<MemberDto> query = em.createQuery(jpql, MemberDto.class);
	
	List<MemberDto> list = query.getResultList();
	for( BookDTO dto : list) {
		System.out.println("dto : " + dto);
	}
}

select 와 from 사이에 new 라는 키워드 뒤에 Dto의 패키지명까지 작성해야 한다.

이 때 new는 객체를 생성하라는 의미가 아니라 JPQL에서 지원하는 new 키워드이다.


반응형

블로그의 정보

슬기로운 개발생활

coco3o

활동하기