본문 바로가기

웹 프로그래밍/JPA

객체 지향 쿼리 언어_기본

JPQL

-JPA를 사용하면 엔티티 객체를 중심으로 개발

-문제는 검색 쿼리

-모든 데이터를 객체로 변환해서 검색하는것은 불가능

-검색 조건이 포함된 SQL이 필요

-JPA는 SQL을 추상화한 JPQL이라는 객체지향 쿼리 언어 제공

-JPQL은 엔티티 객체를 대상으로 쿼리

-SQL을 추상화해서 특정 데이터베이스 SQL에 의존X

-동적 쿼리를 위해 QueryDSL 사용

 

 

JDBC 직접사용 하거나 SpringJdbcTemplate 사용

-JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, 마이바티스등을 함께 사용가능

-단, 영속성 컨텍스트를 적절한 시점에 강제로 플러시 필요(JPA와 관련이 없기 때문임)

 

JPQL 문법

select_문 :: = 

    select_절

    from_절

    [where_절]

    [groupby_절]

    [having_절]

    [orderby_절]

 

update_문 :: = update_절 [where_절]

delete_문 :: = delete_절 [where_절]

 

select m from Member (as) m where m.age > 18

엔티티와 속성은 대소문자 구분함

JPQL 키워드는 대소문자 구분X

엔티티 이름을 사용(테이블  이름이 아님)

별칭은 필수(m)

 

집합과 정렬

select

    COUNT(m), // 회원수

    SUM(m.age), // 나이 합

    AVG(m.age), // 평균 나이

    MAX(m.age), // 최대 나이

    MIN(m.age) // 최소 나이

from Member m

 

TypeQuery: 반환 타입이 명확할때

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

 

결과 조회 API

-query.getResultList(): 결과가 하나 이상일때, 리스트 반환

    -결과가 없으면 빈 리스트 반환

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

    -결과가 둘이상이거나 없으면 Exception 터짐(보장 될때만 써야함)

-반환된 결과는 모두 영속성 컨텍스트에서 관리가 됨

 

파라미터 바인딩 이름기준, 위치 기준

Member result = em.createQuery("select m from Member m where m.username = :username", Member.class).setParameter("username", "member1").getSingleResult();

 

프로젝션

-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(스칼라)

-SELECT DISTINCT로 중복 제거

 

프로젝션 - 여러 값 조회

-SELECT m.username, m.age FROM Member m(스칼라)

    -1. Query 타입으로 조회

    -2. Object[] 타입으로 조회

    -3. new 명령어로 조회

        - 단순 값을 DTO로 바로 조회 SELECT new jpabook.jpql.MemberDTO(m.username, m.age) FROM Member m

        - 패키지 명을 포함한 전체 클래스 명 입력

        - 순서와 타입이 일치하는 생성자 필요

 

페이징 API

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

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

-setMaxRasults(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();

 

조인

-내부 조인: SELECT m FROM Member m [INNER] JOIN m.team t (조인 없으면 안가져옴)

-외부 조인: SELECT m FROM Member m LEFT [OUTER] JOIN m.team t (조인 없어도 null로 가져옴)

-세타 조인: SELECT count(m) from Member m, Team t where m.username = t.name (연관관계 없는 무지성 조인)

 

조인 - ON 절

    -1.조인 대상 필터링

        -SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A' (t.name이 'A'인것만 조인)

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

        -SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name

 

서브 쿼리

-나이가 평균보다 많은 회원

    -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

 

서브 쿼리 지원 함수

-[NOT] EXISTS (subquery): 서브쿼리에 결과가 존재하면 참

-e.g.) select m from Member m where exists (select t from m.team t where t.name = '팀A') 

    -{ALL | ANY | SOME} (subquery)

    -ALL 모두 만족 하면 참

    -e.g.) select o from Order o where o.orderAmount > ALL (select p.stockAmount from Product p)

    -ANY,SOME: 같은 의미, 조건을 하나라도 만족하면 참

    -e.g.) select m from Member m where m.team = ANY (select t from Team t)

-[NOT] IN (subquery): 서브쿼리 결과 중 하나라도 같은것이 있으면 참

 

JPA 서브 쿼리 한계

-JPA 표준 스펙은 WHERE, HAVING 절에서만 서브쿼리 사용 가능

-SELECT 절도 가능(하이버네이트)

-FROM 절의 서브 쿼리는 현재 JPQL에서 불가능

    -조인으로 풀수 있으면 풀어서 해결

 

조건식 - CASE 식

-기본 CASE 식

select

    case when m.age <= 10 then '학생요금'

             when m.age >= 60 then '경로요금'

             else '일반요금'

    end

from Member m

 

-단순 CASE 식(정확한 매칭)

select

    case t.name

          when '팀A' then '인센티브110%'

          when '팀B' then '인센티브120%'

    end '인센티브105%'

from Team t

 

-COALESCE: 하나씩 조회해서 null이 아니면 반환

    -select coalesce(m.username, '이름 없는 회원') from Member m

 

-NULLIF: 두값이 같으면 null반환, 다르면 첫번째 값 반환

    -select NULLIF(m.username, '관리자') from Member m

 

JPQL 기본 함수

-CONCAT

    -select concat('a', 'b') from Member m

-SUBSTRING

    -select substring(m.username, 2, 3) from Member m

-TRIM(L or R 공백 제거)

-LOWER,UPPER

-LENGTH

-LOCATE

    -select locate('de', 'abcdef') from Member m

-ABS, SQRT, MOD

-SIZE, INDEX(JPA 용도)

    -select size(t.members) from Team t

 

사용자 정의 함수 호출

-하이버네이트는 사용전 방언에 추가해야함(DB 방언을 상속받고 사용자 정의 함수 등록)

-select function('group_concat', i.name) from Item i

'웹 프로그래밍 > JPA' 카테고리의 다른 글

JPA 활용(1) 팁 정리  (0) 2023.03.08
객체 지향 쿼리 언어_중급  (0) 2023.03.08
기본값 타입, 임베디드 타입  (0) 2023.03.06
영속성 전이(CASCADE)와 고아 객체  (0) 2023.03.04
즉시로딩과 지연로딩  (0) 2023.03.04