[JPA] 객체 지향 쿼리 언어 - 3

Lee Seung Jae·2021년 7월 25일
0

깃허브 바로가기
책의 내용이 너무많아 계속 분리해서 작성하게 된다.
이번 포스팅에서는 서브 쿼리부터 내용을 다뤄보도록 하겠다.

서브 쿼리

JPQL도 SQL처럼 서브 쿼리를 지원하는데, 여기서는 몇 가지 제약사항이 있다.
서브 쿼리를 WHERE, Having 절에서만 사용할 수 있고 select, from 절에서는 사용할 수 없다.

서브쿼리 함수

  • [NOT] EXISTS 서브쿼리
    • 서브쿼리에 결과가 존재하면 참. NOT은 반대
  • {ALL | ANY | SOME} 서브쿼리
    • 비교 연산자와 같이 사용한다.
      • ALL: 조건을 모두 만족하면 참
      • ANY or SOME : 둘은 같은 의미이다. 조건을 하나라도 만족하면 참
  • [NOT] IN 서브쿼리
    • 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참. 참고로 IN은 서브쿼리가 아닌 곳에서도 사용한다.

조건식

종류설명예제
문자작은 따옴표 사이에 표현, 작은 따옴표를 표현하고 싶다면 작은따옴표 2개('') 사용'Hello', 'He''s'
숫자L(Long), D(Double), F(Float)10L, 10D, 10F
날짜Date {d 'yyyy-mm-dd'}
Time {t 'hh-mm-ss'}
DateTime {ts 'yyyy-mm-dd hh:mm:ss.f'}
{d '2021-07-25'}
{t '15:00:12'}
{ts '2021-07-25 15:48:22.123}
m.createDate = {d '2021-07-25'}
BooleanTRUE, FALSE-
Enum패키지명을 포함한 전체 이름을 사용해야 한다.pack.MemberType.Customer
엔티티 타입엔티티의 타입을 표현한다. 주로 상속과 관련해서 사용한다.TYPE(m) = Member

연산자 우선 순위

  1. 경로 탐색 연산(.)
  2. 수학 연산 : 단항 연산자: +, -, 사칙연산 : *, /, +, -
  3. 비교 연산 : =, >=, >, 등, <>(다름), Between, Like, In, Is Null, Is Empty, Exists
  4. 논리 연산 : NOT, AND, OR

Between

where m.age between 10 and 20
where 뒤에 식으로 작성할 수 있다. Member의 나이가 10~20인 사람 찾기

In

In에는 서브쿼리를 사용할 수 있다. in절의 조건이 하나라도 있으면 참이다.

Like

문자표현식과 패턴을 비교한다.

  • % : 아무 값들이 입력되어도 된다. (값이 없어도 됨)
  • _ : 한 글자는 아무 값이 입력되어도 되지만 값이 있어야 한다.

NULL

Null 인지 비교한다. Null은 =으로 비교하면 안되고 is null을 사용해야 한다.

컬렉션 식

컬렉션에만 사용하는 특별한 기능이다. 컬렉션은 컬렉션 식 이외에 다른 식은 사용할 수가 없다.

Is Empty

컬렉션에 값이 비었으면 참이다.

스칼라 식

위의 수학 연산에 더해 아래와 같은 문자함수도 있다.

함수설명예제
CONCAT(1, 2)문자를 합한다.CONCAT('A','B') = AB
SubString(문자, 위치, [길이])길이 값이 없으면 나머지 전체 길이를 뜻한다.SUBSTRING('ABCDEF', 2, 3) = BCD
TRIM([[LEADING] , TRAILING , BOTH][트림문자] FROM] 문자)LEADING: 왼쪽만, TRAILING: 오른쪽만, BOTH: 양쪽 다 트림 문자를 제거한다. 기본값은 Both, 트림문자 기본값은 공백이다.TRIM(' ABC ') = 'ABC'
LOWER(문자)소문자로 변경
UPPER(문자)대문자로 변경
LENGTH(문자)문자 길이
LOCATE(찾을 문자, 원본 문자, [검색시작위치])검색 위치부터 문자를 검색한다. 1부터 시작, 못 찾으면 0을 반환LOCATE('AB', 'ABCDE') = 1
함수설명
ABS()절대값
SQRT()제곱근
MOD(수학식, 나눌수)나머지
SIZE(컬렉션 값 연관 경로식)컬렉션 크기 구함
INDEX(별칭)LIST 타입 컬렉션의 위치값 구함, 컬렉션이 @OrderColumn을 사용해야 할 수 있다.

날짜 함수는 아래와 같다.

  • Current_Date: 현재 날짜
  • Current_Time: 현재 시간
  • Current_TimeStamp: 현재 날짜 시간

이렇게 보면 DB에서 사용하는 함수가 거의 다 문법이 비슷하게 사용되는 것을 볼 수 있다.

CASE식은 생략하고 추후에 내가 사용할 때 다시 정리해야 겠다.

다형성 쿼리

JPQL로 부모 엔티티를 조회하면 자식 엔티티도 조회된다. Item의 자식으로 Book, Album, Movie 가 있다고 한다면 조회를 했을때 Item을 상속받는 Book, Album, Movie도 조회한다.

이걸 단일 테이블 전략을 사용하면 SQL이 select * from Item 이 되는데
조인 전략을 가져가면 left outer join이 세번 걸리게 된다.

TYPE

TYPE은 엔티티의 상속 구조에서 조회 대상을 특정 자식 타입으로 한정할 때 주로 사용한다.

TREAT

자바의 타입 캐스팅과 빗슷함. 상속 구조에서 부모 타입을 특정 자식 타입으로 다룰 때 사용.
JPA 표준은 FROM, Where 절에서 사용할 수 있지만, Hibernate는 Select 절에서도 Treat를 사용할 수 있다.

사용자 정의 함수 호출

JPA2.1 버전부터 사용자 정의 함수를 지원한다.
문법은 다음과 같다.
function_invocation::= FUNCTION(function_name {, function_arg}*)
예) select function('group_concat', i.name) from Item i

Hibernate 구현체를 사용하면 방언클래스를 상속해서 구현하고 사용할 DB함수를 미리 등록해야 한다.

spring.jpa.hibernate.dialect: org.hibernate.dialect.H2Dialect

방언에따라 dialect 뒤를 해당 SQL로 바꿔서 등록한다.
그렇게 이 구현체를 사용하면 해당하는 함수를 바로 사용할 수 있다.

기타 정리

  • enum은 =비교 연산만 지원한다.
  • 임베디드 타입은 비교를 지원하지 않는다.

Empty String

JPA표준은 ''을 길이가 0인 Empty String으로 정했지만 DB에 따라 ''를 Null로 사용하는 DB가 있으므로 확인하고 사용해야 한다.

Null 정의

  • 조건을 만족하는 데이터가 하나도 없으면 Null
  • Null은 알수 없는 값이다. Null과의 모든 수학적 계산 결과도 Null이 된다.
  • Null == Null 은 알수 없는 값이다.
  • Null is Null은 참이다.

엔티티 직접 사용

기본 키 값

객체 인스턴스는 참조 값으로 식별하고 테이블 로우는 기본 키 값으로 식별한다.
JPQL에서 엔티티 객체를 직접 사용하면 SQL에서는 해당 엔티티의 기본 키값을 사용한다.

Named 쿼리 : 정적 쿼리

  • 동적 쿼리: em.createQuery("") 처럼 JPQL을 문자로 완성해서 직접 넘기는 것을 동적 쿼리라고 한다. 런타임에 특정 조건에 따라 JPQL을 동적으로 구성할 수 있다.
  • 정적 쿼리: 미리 정의한 쿼리에 이름을 부여해서 필요할 때 사용할 수 있는데 Named 쿼리라고 한다. Named쿼리는 한번 정의하면 변경할 수 없는 정적인 쿼리다.

Named쿼리는 애플리케이션 로딩 시점에 JPQL 문법을 체크하고 미리 파싱해둔다. 그래서 오류를 빨리 확인할 수 있고, 사용하는 시점에 결과를 재사용하므로 성능상의 이점도 있다.
Named 쿼리는 정적 SQL이 생성되기 때문에 DB의 성능 최적화에 도움이 된다.
Named 쿼리는 @NamedQuery 를 사용하여 자바 코드에 작성하거나 XML문서에 작성할 수 있다.

  • lockMode: 쿼리 실행 시 락을 건다.
  • hints: 여기서의 힌트는 SQL 힌트가 아니라 JPA 구현체에게 제공하는 힌트이다. 2차 캐시를 다룰때 사용한다.

하나 이상의 NamedQuery를 사용하려면 @NamedQueries 어노테이션 사용할 것.

Named 쿼리를 XML에 정의하는 부분은 XML 대신에 Java에서 많이 하려고 노력하자.

profile
💻 많이 짜보고 많이 경험해보자 https://lsj8367.tistory.com/ 블로그 주소 옮김

0개의 댓글