ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JPA (9) - JPQL (기본문법)
    카테고리 없음 2024. 1. 12. 12:13

     

     

    > jpql은 단순하게 조회가 가능하고, 객체 그래프 탐색으로 쿼리를 날릴 수 있다는 장점이 있다! 

    > JPA는 엔티티 객체 중심 개발이므로, SQL또한 테이블이 아닌 엔티티 객체를 대상으로 검색하도록 돕는다.

    > SQL을 추상화했다. (문법 매우 유사하다) -> JPQL은 엔티티 객체를 대상으로 쿼리를 한다.

     

    *모든 DB 데이터를 객체로 변환하는 것은 불가능하다 -> 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 

    SQL이 필요하다.

     

    String jpql = "select m From Member m where m.name like '%hello%'";
    List<Member> result = em.createQuery(jpql, Member.class).getResultList();

     

    1. JPQL 기본 문법과 기능 

     

    "select m from Member as m where m.age >18"
    
    select 
      COUNT(m), SUM(m.age), AVG(m.age), MAX(m.age), MIN(m.age) from Member m

     

     > 엔티티와 속성은 대소문자 구분한다!! 

     > JPQL 키워드 대소문자X (SELCT ,FROM)

     > 엔티티 이름을 사용한다 (테이블 명이 아니다!)

     > 별칭은 필수 (as 생략 가능)

     > GROUP BY, HAING, ORDER BY 사용 가능 

     

    1.1 TypeQuery, Query

     

    - TypeQuery: 반환 타입이 명확할 때 사용 

    - Query : 반환 타입이 명확하지 않을 때 사용 

    TypedQuery<Member> query = em.createQuery("SELECT m FROM Member m",Member.class);
    
    Query query = em.createQuery("SELECT m.username, m.age FROM Member m");

     

    - 결과 조회 

     

    query.getResultList() : 결과가 하나 이상 -> 결과가 없으면 빈 리스트 반환 

    query.getSingleResult() : 결과가 정확히 하나, 단일 객체 반환

    (결과 없으면: javax.persistence.NoResultException, 둘 이상이면 javax.persistence.NonUniqueResultException)

     

    1.2 파라미터 바인딩 

     

    SELECT m FROM Member m where m.username =:username 
    query.setParameter("username",usernameParam);

     

    > 위치 기반 바인딩도 있는데 그건 쓰지말자 

     

    1.3 프로젝션

     

    > SELECT 절에 조회할 대상을 지정하는 것 

    > 프로젝션 대상 : 엔티티, 임베디드 타입, 스칼라 타입(숫자,문자등 기본 데이터 타입)

     

    SELECT m FROM Member m // 엔티티 프로젝션
    SELECT m.team FROM Member m // 엔티티 프로젝션
    SELECT m.address FROM Member m //임베디드 타입 프로젝션 
    SELECT m.username, m.age FROM Member m // 스칼라 타입 프로젝션 
    
     
     //엔티티 타입 프로젝션 -> 결과 영속성 관리 
     List<Member> selectMember = em.createQuery("select m from Member m where m.username=:username", Member.class)
                        .setParameter("username",member.getUsername())
                        .getResultList();
     Member findMember = selectMember.get(0);
     findMember.setAge(20);
     
     //Member안에 Team 조회 m.team으로 해도 묵시적 join발생 혹은 select m.team from Member (join Team t on m.MEMBER_ID = t.MEMBER_ID)
     //하지만 묵시적 조인은 추후에 알아보기 힘들기 때문에 명시적으로 조인을 써주자
     List<Member> selectMember2 = 
     em.createQuery("select t from Member m join m.team t", Member.class).getResultList();

     

    > DISTINCT로 중복 제거 가능 

     

    > 프로젝션으로 여러 값 조회(여러 스칼라와 같이)

     

    SELECT m.username, m.age FROM Member m

     

     -> Query 타입으로 조회

    Query query = em.createQuery("SELECT m.username, m.age FROM Member m");

     

     -> Object[] 타입으로 조회 (결과 하나당 Object[]배열에 담겨나옴)

    List<Object[]> objectResult = em.createQuery("SELECT m.username, m.age FROM Member m").getResultList();
    
    for(Object[] result : objectResult){
    
    	//..result[0],result[1]
    }

     

     -> new 명령어로 조회 (DTO 사용)

     

    List<MemberDTO> results = em.createQuery("SELECT new jpql.MemberDTO(m.username,m.age) from Member m",MemberDTO.class)
                              .getResultList();

     

     > 패키지명 포함한 전체 클래스명 입력, 순서와 타입이 일치하는 생성자 필요하다.

     > 해당 데이터를 자주 조회하는 경우 위 방식을 고려해보자 

     

     

    2. 페이징 API

     

    > JPA는 페이징을 다음 두 API로 추상화

       setFirstResult(int startPosition) : 조회 시작 위치

       setMaxResults(int maxResult) : 조회할 데이터 수 

     

    String jpql = "select m from Member m order by m.name desc";
    List<Member> resultList = em.createQuery(jpql,Member.class)
                              .setFirstResult(10)
                              .setMaxREsults(20)
                              .getResultList();

     

    3. 조인

     

    내부조인 : SELECT m FROM Member m [INNER] JOIN m.team t;

    외부조인 : SELECT m FROM Member m LEFT [OUTER] JOIN m.team t

    세타 조인: SELECT count(m) FROM Meber m, Team t where m.username = t.name

     

    > ON 절을 활용한 조인 

       - 조인 대상 필터링 

         - 연관관계 없는 엔티티 외부조인 

    //회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인
    SELECT m,t FROM Member m LEFT JOIN m.team t on t.name = 'A' // 약간 on 하기 전에 조건넣기
    
    
    SELECT m,t FROM Member m LEFT JOIN Team t on m.username = t.name //연관관계 없는 열 조인

     

    4. 서브쿼리 

     

    //나이가 평균보다 많은 회원 (서브쿼리랑 메인쿼리 관련 없음 -> 성능상 좋다)
    select m from Member m
    where m.age > (select avg(m2.age) from Member m2);
    
    //한 건이라도 주문한 고객 (서브쿼리에 메인쿼리 넣기)
    select m from Member m where (select count(o) from Order o where m=o.member) > 0

     

     

     -> 서브 쿼리 지원 함수 (EXSIST,ALL,ANY,SOM,IN 지원) 

     

    //팀A 소속인 회원
    
    SELECT m FROM Member m WHERE exsist(select t from m.team t where t.name ='팀A'); //m.team이면 조인해서 가져옴
    
    //전체 상품 각각의 재고보다 주문량이 많은 주문들 
    SELECT o From Order o where o.orderAmount > ALL (select p.stockAmount from Product p)
    
    //어떤 팀이든 팀에 소속된 회원 
    select m from Member m where m.team = ANY(select t from Team t)

     

    > JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능 (SELECT 절은 하이버네이트 지원, FROM도 하이버네이트)

     

     

    5. JPQL 타입 표현  

     

    > 문자 : 'HELLO', 'SEH''s' // '표현하고 싶으면 ''두개 

    > 숫자 : 10(LONG), 10D(Double), 10F(Float)

    > Boolean : TRUE, FALSE 

    > ENUM : jpabook.MemberType.Admin (패키지명 포함)

    > 엔티티타입: TYPE(m) = Member(상속관계에서 사용)

     

    //ENUM타입
    String query="select m.username,'HELLO',TRUE From Member m WHERE m.type = jpql.MemberType.ADMIN";
     String query="select m.username,'HELLO',TRUE From Member m WHERE m.type = :type";
     List<Object[]> result = em.createQuery(query).setParameter("type",MemberType.ADMIN).getResultList();
    
    일케 바꾸기 가능 setPArameter
    
    //상속관계에서 Item을 뽑는데 조건으로 자식 사용
     em.createQuery("select i from Item i where type(i) = Book");

     

     

    > CASE식 

    SELECT 
       case when m.age <= 10 then '학생요금'
       case when m.age >= 60 then '경로요금'
       else '일반요금'
      end
      from Member m
      
     SELECT 
      case t.name
      when '팀A' then
      //..
     end
     FROM Team t
     
     
     select coalesce(m.username, '이름 없는 회원') from Member m //하나씩 조회해서 null이 아니면 반환
     select NULLIF(m.username, '관리자') from Member m // 두 값이 같으면 null 다르면 첫번째 값 반환
     //유저명이 관리자면 null 아니면 유저명

     

     

    > JPQL 기본 함수 (JPQL 표준 DB와 상관없이 사용가능)

     

    - CONCAT, SUBSTRING, TRIM, LOWER, UPPER, LENGTH, LOCATE(IndexOf),ABS,SQRT,MOD

    - SIZE,INDEX(JPA 용도)

     

    * 사용자 정의 함수 호출 가능 -> 사용자 정의함수 만드는 방법은 필요시 찾아보자..

    select function('group_concat',i.name) from Item i //사용자 정의함수 호출
Designed by Tistory.