JPQL (JAVA PERSISTENCE QUERY LANGUAGE)

Java EE 2007/01/22 18:33 Posted by Sun

JPQL (JAVA PERSISTENCE QUERY LANGUAGE)
글쓴이: Jie Lin Leng

Java Persistence API(http://java.sun.com/javaee/technologies ··· ence.jsp)는 사용자가 엔티티 및 해당 퍼시스턴스 상태에 대한 쿼리를 정의할 수 있게 해주는 질의어를 지정한다. 또한 JPQL(Java Persistence Query Language)이라 불리는 이 질의어는 엔터프라이즈 환경에서 사용하는 특정 데이터베이스와는 별도로 이식 가능한 방법으로 쿼리의 의미를 지정할 수 있게 해준다.

본 테크 팁에서는 Java Persistence Query Language를 소개하고 기본 기능에 관해 알아보도록 한다. 본 팁은 독자가 Java Persistence API의 기본 용어와 개념을 이미 이해하고 있는 것으로 가정하는데, 그렇지 않은 경우에는 Java EE 5 Tutorial의 "Chapter 24: Introduction to the Java Persistence API(영문)(http://java.sun.com/javaee/5/docs/tutor ··· 3wp78460)"를 참조하기 바란다.

본 팁에는 예제 패키지가 첨부되어 있으며, 팁의 코드 예제들은 패키지에 포함되어 있는 예제 소스 코드에서 발췌한 것이다. 예제에는 Java EE 5 SDK를 사용했으며, Java EE 5 SDK는 Java EE 다운로드 페이지에서 다운로드할 수 있다.
http://java.sun.com/javaee/downloads/index.jsp

예제

먼저 Java Persistence Query Language 사용에 관한 보기를 살펴보기로 하자. 사용자가 2개의 엔티티 Customer과 Order를 가지고 있고 이들이 서로 One-to-Many(일 대 다) 관계를 가진다고 가정하자. 아울러, Customer 엔티티 클래스와 Order 엔티티 클래스가 다음과 같이 정의된다고 가정해보자.

@Entity
   @Table(name="CUSTOMER_TABLE")
   public class Customer implements Serializable{

       public enum CustomerStatus
         {FULL_TIME, PART_TIME, CONTRACT};
       @Id
       @Column(name="ID")
       private Integer customerId;
       @Column(name="CITY")
       private String city;
       @Column(name="NAME")
       private String name;
       @Enumerated(ORDINAL)
       @Column(name="STATUS")
       private CustomerStatus status;
       @OneToMany(mappedBy="customer")
       private Collection<Order> orders;

       ...
       }

   @Entity
   @Table(name="ORDER_TABLE")
      public class Order implements Serializable {
    
      @Id
      @Column(name="ID")
      private Integer orderId;
      @Column(name="QUANTITY")
      private int quantity;
      @Column(name="TOTALPRICE")
      private float totalPrice;
      @ManyToOne()
      @JoinColumn(name="CUST_ID")
      private Customer customer;

        ...
   }

다음은 이들 엔티티의 인스턴스를 생성하고, 해당 퍼시스턴스를 관리하기 위한 엔티티 매니저를 생성하고, 인스턴스를 데이터베이스에 삽입하는 클라이언트 코드이다.

// Create an EntityManagerFactory for a persistence unit
   // called j2seEnvironment.
   EntityManagerFactory emf =
   Persistence.createEntityManagerFactory("j2seEnvironment");

   // Create an Entity Manager
   EntityManager em = emf.createEntityManager();
  
   // get a Transaction
   EntityTransaction tx = em.getTransaction();
  
   // create a POJO instance of the Customer class
   Customer customer = new Customer();
   customer.setCustomerId(new Integer(3));
   customer.setName("SUN_SALE");
   customer.setCity("SAN JOSE");
   customer.setStatus(Customer.CustomerStatus.FULL_TIME);
          
   // create a POJO instance of the Order class
   // for this customer
   Order order = new Order();
   order.setOrderId(new Integer(3));
   order.setQuantity(new Integer(2));
   order.setTotalPrice(new Float(22.30));
   order.setCustomer(customer);
          
   // Make the Customer and Order instances persistent
   // and insert them into the database
   tx.begin();
   em.persist(customer);
   em.persist(order);
   tx.commit();

엔티티의 퍼시스턴스가 확보되면 해당 엔티티에 대해 Java Persistence Query Language 쿼리를 발행할 수 있다. 예를 들어, 다음은 이름이 "SUN_SALE"인 Customer 엔티티 인스턴스 내의 모든 요소를 열거하기 위해 클라이언트 코드에 추가할 수 있는 간단한 쿼리이다.

// run a simple Java Persistence query language query
   String ejbql = "SELECT c FROM Customer c
   WHERE c.name = 'SUN_SALE'";
   Query query = em.createQuery(ejbql);
   List result = query.getResultList();


네임드 쿼리(Named Query)

사용자는 또한 엔티티에 대한 쿼리를 미리 정의할 수 있는데, 이렇게 정의된 정적 쿼리를 네임드 쿼리(named query)라고 한다. 네임드 쿼리를 사용할 때의 주요 이점은 이를 여러 차례 재실행하면서 각각의 실행에 대해 서로 다른 매개변수를 제공할 수 있다는 점이다.

네임드 쿼리를 사용하려면 먼저 @NamedQuery 주석을 이용하여 네임드 쿼리를 정의해야 하는데, 이 작업은 엔티티를 정의하기 전에 해당 엔티티 클래스에서 수행하도록 한다. 예를 들어, 다음은 Customer 클래스에서 정의된 네임드 쿼리이다.


 @NamedQuery (
       name="findCustomerByName",
       query="select c FROM Customer c WHERE c.name = :name"
   )
   })

   public class Customer {
   ...
   }

네임드 쿼리 findCustomerByName은 네임드 파라미터 :name에 의해 이름이 제공되는 Customer 엔티티 인스턴스 내의 모든 요소를 검색한다. Java Persistence Query Language의 네임드 파라미터를 구성하는 콜론 뒤에는 식별자가 붙어있다.

네임드 쿼리는 또한 @NamedQueries 주석을 이용하여 한데 묶을 수도 있다. 예:

@NamedQueries({
   @NamedQuery (
       name="findCustomerByName",
       query="select c FROM Customer c WHERE c.name = :name"
   ),
   @NamedQuery(
       name="findCustomerbyOrderId",
       query="select c FROM Customer c JOIN c.orders o WHERE
               o.orderId = :id"
   )
   })

   public class Customer {
   ...
   }
  
두 번째 네임드 쿼리 findCustomerOrder는 네임드 파라미터 :orderId에 의해 Order 식별이 제공되는 주문을 가지는 Customer 엔티티 내의 모든 요소를 검색한다.

쿼리 이름은 퍼시스턴스 유닛에 스코핑(scoped)되는데, 다시 말해서 이 이름들은 엔티티 매니저에 의해 관리되는 엔티티 클래스(이 경우에는 Customer 및 Order)에 적용된다.

네임드 쿼리를 정의한 후에는 EntityManager의 createNamedQuery 메소드를 이용하여 클라이언트 코드에서 이를 생성한다. 예:

 List customers = em.createNamedQuery("findCustomerByName")
   .setParameter("name", "SUN_SALE")
   .getResultList();

findCustomerByName의 setParameter 메소드는 이름 인자를 네임드 쿼리 정의 내의 네임드 파라미터 :name에 바인드하고, getResultList 메소드는 쿼리 결과를 반환한다(이 경우, 이름이 "SUN_SALE"인 Customer 엔티티 내의 모든 요소).


GROUP BY 및 HAVING 절

Java Persistence Query Language는 또한 GROUP BY와 HAVING 절을 지원하는데, GROUP BY 절은 일련의 속성에 따라 값들을 집계할 수 있게 해주고, HAVING 절은 쿼리 결과를 추가로 제한할 수 있게 해준다.

GROUP BY와 HAVING 절은 몇 가지 특수한 요구사항을 가진다. 즉, SELECT 절에 표시되는 모든 항목(집계 함수에 대한 인자 제외)은 반드시 GROUP BY 절에도 표시되어야 하고, HAVING 절 내의 조건식은 반드시 그룹 항목 또는 그룹 항목에 적용된 집계 함수에 걸쳐 지정되어야 한다.

다음은 GROUP BY 또는 HAVING 절을 사용하는 몇 가지 보기이다.

// Group the orders by their customer and for each group
   // return the customer and the average totalPrice
   String ejbql = "SELECT o.customer, AVG(o.totalPrice)
       FROM Order o GROUP BY o.customer";
   Query query = em.createQuery(ejbql);

   // Group the customers by their city. For each group return
   // the city and the number of customers in that group, but
   // only if there are more than 3
   String ejbql = "SELECT c.city, COUNT(c.city)
       FROM Customer c GROUP BY c.city HAVING COUNT(c.city) > 3";
   Query query = em.createQuery(ejbql);

   // Group the orders with a totalPrice over a certain limit
   // per the name of their customer, but consider only
   // customers whose name starts with 'SUN'). For each group
   // return the customer name, the average, and maximum
   // totalPrice.
   String ejbql = SELECT o.customer.name, AVG(o.totalPrice),
     MAX(o.totalPrice)
       FROM Order WHERE o.totalPrice > :limit
       GROUP BY o.customer.name HAVING o.customer.name LIKE 'SUN%';
   Query query = em.createQuery(ejbql);

그 밖의 여러 기능

Java Persistence Query Language는 완전 구조화된 질의어로, 본 팁에서 다룬 것 외에도 수많은 언어 기능을 제공하며, 여기에는 대규모 업데이트 및 삭제 연산, outer join 연산, 프로젝션, 서브쿼리 등을 위한 언어 기능이 포함된다. 자세한 내용은 Java EE Tutorial의 "Chapter 27: The Java Persistence Query Language(영문)"를 참조하기 바란다.
http://java.sun.com/javaee/5/docs/tutor ··· 3wp80587

다음 팁에서는 Java Persistence Query Language 쿼리 작성 시 흔히 빠질 수 있는 함정에 대해 다루어본다.

예제 코드 실행하기

본 팁에 첨부된 예제 코드를 실행하려면 다음 단계를 수행한다.

1. Java EE 5 SDK를 아직 구하지 못했다면 Java EE 다운로드 페이지에서 다운로드 받아 설치한다.

2. 아래의 환경 변수를 설정한다.
- JAVAEE_HOME. Java EE 5 SDK의 설치 장소를 표시해야 한다.
- ANT_HOME ant의 설치 장소를 표시해야 한다. ant는 다운로드한 Java EE 5 SDK 번들에 포함되어 있다. (Windows에서는 lib\ant 서브디렉토리에 위치함.)
- JAVA_HOME. 사용자 시스템에서의 JDK 5.0 위치를 표시해야 한다. JDK는 다운로드한 Java EE 5 SDK 번들에 포함되어 있다. (Windows에서는 jdk 서브디렉토리에 위치함.)

PATH 환경 변수에 $JAVA_HOME/bin, $ANT_HOME/bin 및 $JAVAEE_HOME/bin을 추가한다.

3. 예제 패키지를 다운로드하여 압축을 푼다. ttdec2006jpql 아래의 JPQL 디렉토리에는 예제를 위한 소스 파일과 기타 지원 파일이 포함되어 있다.

4. JPQL 디렉토리로 이동하여 build.xml 파일을 적절히 편집한다. 예를 들어, javaee.home의 값을 Java EE 5 SDK가 설치된 곳으로 설정한다.

5. 데이터베이스 서버를 시작한다. 위에 표시된 코드는 본 테크 팁의 텍스트 버전에서 캡쳐할 수 있다.
 
$JAVAEE_HOME/bin/asadmin start-database

   In response you should see output similar to this:
  
      ...

      start-db:
           [exec] Database started in Network Server mode on host
           ... and port ...
     
           [exec] Starting database in the background.  Log
           redirected to ...
           [exec] Command start-database executed successfully.

6. 예제 애플리케이션을 구축하고 실행한다. JPQL 디렉토리에서 아래 명령어를 입력한다.

nt all

   In response you should see output similar to this:
     
      ...
      
           [java] JPQL simple query SELECT c FROM Customer c WHE
      RE c.name = 'SUN_SALE returns Customers: [ejbql.models.Cus
      tomer@9cbd4b]
           [java] JPQL query with Named Query SELECT c FROM Cust
      omer c WHERE c.name = 'SUN_SALE' returns Customers: [ejbql
      .models.Customer@9cbd4b]
           [java] JPQL query with GROUP BY SELECT o.customer, AV
      G(o.totalPrice) FROM Order o GROUP BY o.customer returns [
      [Ljava.lang.Object;@c44b88, [Ljava.lang.Object;@13ad33d]
           [java] JPQL query with GROUP BY SELECT c.city, COUNT(
      c.city) FROM Customer c GROUP BY c.city HAVING COUNT(c.cit
      y) > 1 returns [[Ljava.lang.Object;@16921fd
           [java] JPQL query with GROUP BY SELECT o.customer.nam
      e, AVG(o.totalPrice), MAX(o.totalPrice) FROM Order o WHERE
      o.totalPrice > :limit GROUP BY o.customer.name HAVING o.cu
      stomer.name LIKE 'SUN%' returns [[Ljava.lang.Object;@1acd4
      7, [Ljava.lang.Object;@19b04e2]

----------------------------------------------------


-샘플 아카이브 다운로드 받기-
JPQL (JAVA PERSISTENCE QUERY LANGUAGE)
http://java.sun.com/mailers/techtips/en ··· jpql.zip

"Java EE" 카테고리의 다른 글

2007/01/22 18:33 2007/01/22 18:33

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/338

댓글을 달아 주세요

  1. 고진구  수정/삭제  댓글쓰기

    쉬운 예제와 설명 잘 읽었읍니다. 큰 도움이 되겠어요.

    2007/09/09 23:03
  2. 신경남  수정/삭제  댓글쓰기

    캡처하는 방법까지. 정말 큰 도움이 되었습니다.

    2007/09/18 10:53
  3. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 04:01
[로그인][오픈아이디란?]

◀ Prev 1  ... 314 315 316 317 318 319 320 321 322  ... 626  Next ▶