9. 객체 지향 쿼리 언어 1 - 기본 문법

1. 소개

  • JPQL
List<Member> result = em.createQuery(
                    "select m From Member m where m.username like '@kim'",
                    Member.class
).getResultList();
for (Member member: result) {
     System.out.println("member = " + member);
}
  • Criteria
    • 오류를 발견하기 쉽다.
    • 동적 쿼리를 생성하기 쉽다.
    • sql같지가 않다 -> 유지보수가 안됨 -> 잘 쓰지 않는다
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> resultList = em.createQuery(cq).getResultList();
  • QueryDSL
    • 동적 쿼리 작성 편리
    • 단순하고 쉽다
    • 실무 사용 권장
JPAFactoryQuery query = new JPAQueryFactory(em);
 QMember m = QMember.member;
 List<Member> list =
 query.selectFrom(m)
 .where(m.age.gt(18))
 .orderBy(m.name.desc())
 .fetch();
  • 네이티브 SQL
em.createNativeQuery("select MEMBER_ID, CITY, STREET, ZIPCODE, USERNAME from Member")
                    .getResultList();
  • 쿼리를 실행할 때 em.flush()가 자동으로 실행
    • db conn.query는 flush 실행을 안하므로 강제로 flush를 해줘야한다.

2. JPQL 기본 문법과 쿼리 API

  • JPQL은 SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다
  • select m from Member as m where m.age> 18
    • Member -> 엔티티
  • 엔티티와 속성은 대소문자 구분 O
  • JPQL 키워드는 대소문자 구분 X
  • 엔티티 이름 사용 테이블 이름 X
  • 별칭은 필수 AS는 생략 가능
  • count. avg, sum 다 사용 가능
  • TypeQuert -> 반환 타입이 명확할 때 사용 & Query -> 반환 타입이 명확하지 않을 때 사용
em.createNativeQuery("select MEMBER_ID, CITY, STREET, ZIPCODE, USERNAME from Member")
                    .getResultList();
  • 결과가 컬렉션이면 getResultList()
    • 결과가 없으면 빈 리스트 반환
  • 결과가 객체면 getSingleResult()
    • 결과가 없으면 javax.persistence.NoResultException
    • 결과가 둘 이상이면 javax.persistence.NoUniqueException
  • 파라미터 바인딩 -> 위치 기반, 이름 기반이 있지만 위치기반을 추천
TypedQuery<Member> query = em.createQuery("select m from Member m where m.username = :username", Member.class)
                    .setParameter("username", "hello");
Member singleResult = query.getSingleResult();
System.out.println("singleResult = " + singleResult);

3. 프로젝션

  • select 절이 조회할 대상을 지정
  • 종류
    - SELECT m FROM Member m → 엔티티 프로젝션
    - SELECT m.team FROM Member m → 엔티티 프로젝션
    - SELECT m.address FROM Member m → 임베디드 타입 프로젝션
    - SELECT m.age, m.username FROM Member m → 스칼라 타입 프로젝션
    - 프로젝션으로 데이터를 추출할 시 영속성 컨테이너에서 관리 -> 수정 및 삭제 가능
  • 스칼라 타입 프로젝션
  • Query 타입
List resultList = em.createQuery("select m.username, m.age from Member m ").getResultList();

for (Object o : resultList) {
    Object obj = o;
    Object[] result = (Object[]) obj;
    System.out.println("obj[0] = " + result[0]);
    System.out.println("obj[1] = " + result[1]);
}
  • TypeQuery 타입
List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m ").getResultList();
  • new 명령어로 조회
List<MemberDTO> result = em.createQuery("select new jpql.MemberDTO(m.username, m.age) from Member m ", MemberDTO.class)
                    .getResultList();

MemberDTO memberDTO = result.get(0);
System.out.println("memberDTO.getUsername() = " + memberDTO.getUsername());
System.out.println("memberDTO.getAge() = " + memberDTO.getAge());

4. 페이징

  • setFirstResult -> 조회 시작 위치 & setMaxResult -> 조회할 데이터 수
List<Member> result = em.createQuery("select m from Member m order by m.age desc", Member.class)
                    .setFirstResult(0)
                    .setMaxResults(10)
                    .getResultList();
System.out.println("result = " + result.size());
for (Member member1 : result) {
    System.out.println("member1 = " + member1.toString());
}

5. 조인

String query = "select m from Member m inner join m.team t";
List<Member> result = em.createQuery(query, Member.class)
        .getResultList();
  • On 절
    • 조인 대상 필터링
    • 연관관계 없는 엔티티 외부 조인 가능
String query = "select m from Member m left join m.team t on t.name = 'teamA'";
List<Member> result = em.createQuery(query, Member.class)
        .getResultList();

6. 서브 쿼리

  • JPA 서브 쿼리 한계
    • where, having 절에서만 서브 쿼리 가능
    • From 절의 서브 쿼리는 현재 JPQL에서 불가능
      • 조인으로 해결, 쿼리를 두번 날리는 식으로 해결

7. JQPL 타입 표현과 기타식

  • ENUM
String query = "select m.username, 'hello', true from Member m "
                    + "where m.type = jpql.MemberType.ADMIN";
List<Object []> result = em.createQuery(query)
      .getResultList();
  • 상속관계에서 해당하는 타입만 가져오고 싶다
"select i from Item i where type(i) = Book"

8. 조건식 - CASE 식

  • CASE
String query = "select" +
	              " case when m.age <= 10 then '학생요금'"+
	              " when m.age >= 60 then '경로요금'"+
	              " else '일반요금'"+
	              " end" +
	              " from Member m";
  • COLALESE -> 하나씩 조회해서 NULL이 아니면 반환
String query = "select coalesce(m.username, '이름 없는 회원') from Member m";

9. JPA 기본 함수

  • concat, substring, trim, lower, upper, length, locate
  • 사용자 함수 지정
    • dialect 디렉토리 생성
    • MyH2Dialect 클래스 생성 후
    • 함수 생성 코드 참조 후 작성
    • select function('함수 이름') ~~~으로 사용

좋은 웹페이지 즐겨찾기