📌 1. JPQL

  • JPQL : Java Persistence Query Language
  • 가장 단순한 조회 방법
    • JPA를 사용하면 엔티티 객체를 중심으로 개발하게 된다.
    • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.
    • JPA는 JPQL을 분석한 후 적절한 SQL을 만들어서 데이터베이스를 조회한다.
  • JPQL과 SQL 비교
    • SQL : 데이터베이스 테이블을 대상으로 쿼리
    • JPQL : 엔티티 객체를 대상으로 쿼리
      • SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않음
      • SQL과 문법 유사(select, from, where, group by, having, join 지원)

📍 1-1. JPQL 기본 사용법

  • 대소문자 구분
    • 엔티티와 속성은 대소문자를 구분한다.
    • JPQL 키워드는 구분하지 않는다.
  • 엔티티 이름
    • 테이블명 대신 엔티티명을 사용한다.
      • @Entity(name="")으로 설정 가능
      • 지정하지 않을 시 클래스 명을 기본값으로 사용(추천)
  • 별칭(Alias) 필수
    • JPQL에서 별칭은 필수이며, AS는 생략할 수 있다.

📍 1-2. JPQL 문법

  • SELECT문
    select
    from
    where
    group by
    having
    orderby

    • 예시 : select m from Member as m where m.age > 18
      • 엔티티 속성 : 대소문자 구분 (Member, age)
      • JPQL키워드 : 대소문자 구분 X (select, from, where)
  • UPDATE
    update
    where

  • DELETE
    delete
    where

  • 집계함수

    select 	count(m)	// 회원수
    			sum(m.age)	// 나이 합
    			avg(m.age)	// 나이 평균
    			max(m.age)	// 나이 최대값
    			min(m.age)	// 나이 최소값
    from Member m

📍 1-3. 반환 타입 지정

  • TypeQuery : 반환 타입이 명확할 때 사용한다.
    • 예시
      TypeQuery<Member> query 
      	= em. createQuery("select m from Member m", Member.class);
  • Query : 반환 타입이 명확하지 않을 때 사용한다.
    • 예시
      Query query = 
      	em.createQuery("select m.username, m.age from Member m");

📍 1-4. 결과 조회

  • query.getResultList() : 결과가 하나 이상일 때 리스트 반환
    • 결과가 없으면 빈 리스트를 반환한다.
      • collection이 반환되기 때문에 NullPointerException에 대한 걱정은 하지 않아도 된다.
  • query.getSingleResult() : 결과가 정확히 하나일 때 단일 객체 반환
    • 결과값이 정확히 하나 존재하지 않으면 예외가 발생한다.
      • 결과가 없으면 : javax.persistence.NoResultException
      • 결과가 둘 이상이면 : javax.persistence.NonUniqueResultException 발생

📍 1-5. 파라미터 바인딩

  • 이름 기준
    select m from Member m where m.username = :username
    query.setParameter("username",usernameParam);
    // 메시지 체인 방식 예시
    Member result
    	= em.createQuery("select m from Member m where m.username = :username", Member.class)
    		.setParameter("username","member1")
    		.getSingleResult();  
  • 위치기준
    // 권장되지 않음
    select m from Member m where m.username = ?1
    query.setParameter(1,usernameParam);

📍 1-6. 프로젝션

  • 프로젝션 : SELECT 절에 조회할 대상을 지정하는 것

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

    • 엔티티 프로젝션

      // Member 엔티티 조회
      List<Member> result = em.createQuery("select m from Member m", Member.class)
      						.getResultList();
      // Member와 관련된 Team 조회(실제 sql 입장에서는 join결과가 발생)
      // 직관적이지 않아 권장하지 않음
      List<Team> result2 = em.createQuery("select m.team from Member m", Team.class)
      						.getResultList();
      // join문으로 Team 조회
      List<Team> result2 = em.createQuery("select t from Member m join m.team t", Team.class)
      						.getResultList(); 
    • 임베디드 타입 프로젝션

      // 직접 가져올 수 없고 o.address가 소속되어 있는 엔티티에서 가지고 와야 한다
      em.createQuery("select o.address from Order o", Address.class)
      					.getResultList();
    • 스칼라 타입 프로젝션

      // 여러 값 조회 - 1단계
      List resultList = em.createQuery("select m.username, m.age from Member m")
      					.getResultList();
      // 타입을 지정하지 못하므로 object 받아오기
      Object[] result1 = (Object[])resultList.get(0);
      // 여러 값 조회 - 2단계
      List<Object[]> resultList2 = em.createQuery("select m.username, m.age from Member m")
      								.getResultList();
      Object[] result2 = resultList2.get(0); 		
      // 여러 값 조회 - 3단계(DTO 사용 / 가장 권장)
      // 생성자를 호출하는 듯한 문법, 패키지 경로까지 명시
      List<MemberDTO> result3 = em.createQuery
      	("select new com.codingbox.jpql.MemberDTO(m.username, m.age) from Member m")
      						.getResultList();
      MemberDTO memberDTO = result3.get(0); 

📍 1-7. 페이징 API

  • JPA는 페이징을 다음 두 API로 추상화한다.
    • setFirstResult(int startPosition) : 조회 시작 위치(0부터 시작)
    • setMaxResults(int maxResult) : 조회할 데이터 수
      => 몇 번째부터 몇 개의 데이터를 조회할 것인가
        // 나이순으로 멤버 조회
        	String jpql = "select m from Member m order by m.age desc";
        // 10번째 자료부터 20개 자료 조회
      	List<Member> resultList = em.createQuery(jpql,Member.class)
      								.setFirstResult(10)
      								.setMaxResults(20)
      								.getResultList();
        // 20개 크기의 멤버 리스트가 조회됨
      	System.out.println("result.size : " + resultList.size());
      	for(Member member : resultList) {
      		System.out.println("member = " + member);
      	}

📍 1-8. 조인

  • 객체 스타일의 문법을 가진다. (대괄호는 생략가능)
  • 내부 조인
    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 Member m, Team t where m.username = t.name

📍 1-9. 서브 쿼리

  • SQL과 같이 서브 쿼리를 조건절로 사용 가능하다.
    select m from Member m where m.age > (select avg(m2.age) from Member m2)

0개의 댓글