Spring

객체 지향 쿼리 언어(2)

codingtori 2025. 6. 1. 23:39

QueryDSL

  • 쿼리를 문자가 아닌 코드로 작성해도, 쉽고 간결하며 그 모양도 쿼리와 비슷하게 개발할 수 있는 프로젝트
  • Criteria처럼 JPQL 빌더 역할을 함
  • 이름 그대로 쿼리 즉 데이터를 조회하는 데 기능 특화됨
  • querydsl-jpa: QueryDSL JPA 라이브러리
  • querydsl-apt: 쿼리 타입(Q)을 생성할 때 필요한 라이브러리

QueryDSL을 사용하려면 Criteria의 메타 모델처럼 엔티티를 기반으로 쿼리 타입이라는 쿼리용 클래스 생성 필요

또한, com.mysema.query.jpa.impl.JPAQuery 객체 생성 필요 (→이때 엔티티 매니저를 생성자에 넘겨줌)

 

 

기본 Q 생성

쿼리 타입(Q)은 사용하기 편리하도록 기본 인스턴스를 보관하고 있음

별칭을 직접 지정해서 사용 필요

 

검색 조건 쿼리

QueryDSL의 where 절에는 and나 or, 여러 검색 조건 사용 가능

 

결과 조회

쿼리 작성 → 결과 조회 메소드 호출 → 실제 DB 조회

uniqueResult() , list() 사용 + (파라미터 = 프로젝션 대상)

 

  • uniqueResult() : 조회 결과가 한 건일 때 사용. 조회 결과가 없으면 null 반환 & 결과가 하나 이상이면 com.mysema.query.NonUniqueResultException 예외 발생
  • singleResult() : uniqueResult()와 같지만 결과가 하나 이상이면 처음 데이터를 반환
  • list() : 결과가 하나 이상일 때 사용. 결과가 없으면 빈 컬렉션 반환

페이징과 정렬

  • 정렬 : orderBy -- asc() / desc()
  • 페이징 : offset, limit

그룹

groupBy 사용, 그룹화된 결과 제한 시 having 사용

 

조인

innerJoin(join), leftJoin, rightJoin, fullJoin && JPQL의 on && fetch 조인

첫 번째 파라미터에 조인 대상을 지정 && 두 번째 파라미터에 별칭으로 사용할 쿼리 타입 지정

query.from(order)
	.join(order.member, member)
	.leftJoin(order.orderItems, orderItem)
    .innerJoin(order.member, member).fetch()
    .leftJoin(order.orderItems, orderItem).fetch()
    .list(order);

 

서브 쿼리

- com.mysema.query.jpa.JPASubQuery 생성

- 하나면 unique(), 여러 건이면 list() 사용

 

프로젝션

select 절에 조회 대상을 지정하는 것

 

- 하나인 경우 : 해당 타입으로 반환

- 여러 필드 선택 시 : com.mysema.query.Tuple이라는 내부 타입 사용

 

빈 생성

쿼리 결과를 엔티티가 아닌 특정 객체로 받고 싶을 때 사용

- 프로퍼티 접근

- 필드 직접 접근

- 생성자 사용

com.mysema.query.types.Projections사용

 

동적 쿼리

com.mysema.query.BooleanBuilder 사용

 

메소드 위임

쿼리 타입에 검색 조건을 직접 정의 가능

정적 메소드 만들기 → @com.mysema.query.annotations.QueryDelegate 어노테이션에 속성으로 이 기능을 적용할 엔티티 지정

 

 

네이티브 SQL

 

- 특정 데이터베이스만 사용하는 함수

- 특정 데이터베이스만 지원하는 SQL 쿼리 힌트

- 인라인 뷰(From 절에서 사용하는 서브쿼리), UNION, INTERSECT

- 스토어 프로시저

- 특정 데이터베이스만 지원하는 문법

 

이렇게 JPQL을 사용할 수 없을 때 JPA가 SQL을 직접 사용할 수 있는 기능을 제공하는 것

//값 조회
Query nativeQuery = em.createNativeQuery(sql)

//결과 매핑 사용
Query nativeQuery = em.createNativeQuery(sql, "memberWithOrderCount");

 

결과 매핑 어노테이션

- @SqlResultSetMapping 

- @EntityResult

- @FieldResult

- @ColumnResult

 

Named 네이티브 SQL = 정적 SQL 작성

 

스토어드 프로시저

- proc_multiply : 단순히 입력 값을 두 배로 증가시켜 줌

- em.createStoredProcedureQuery()

- Named 스토어드 프로시저 : 스토어드 프로시저 쿼리에 이름을 부여해서 사용하는 것 (@NamedStoredProcedureQuery로 정의 && name속성으로 이름 부여)

 

벌크 연산

여러 건을 한 번에 수정하거나 삭제하는 연산

- executeUpdate() : 벌크 연산으로 영향을 받은 엔티티 건수 반환

 

* 주의점 *

벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리한다

 

* 해결법 *

- em.refresh() 사용

- 벌크 연산 먼저 실행

- 벌크 연산 수행 후 영속성 컨텍스트 초기화

 

JPQL의 특징

  • JPQL은 항상 데이터베이스 조회
  • JPQL로 조회한 엔티티는 영속 상태
  • 영속성 컨텍스트에 이미 존재하는 엔티티가 있으면 기존 엔티티 반환

플러시 모드

플러시 : 영속성 컨텍스트의 변경 내역을 DB에 동기화 하는 것

JPQL은 영속성 컨텍스트에 있는 데이터 고려하지 않고 DB에서 데이터 조회

→ JPQL 실행 전 영속성 컨텍스트의 내용을 DB에 반영해야함

 

  • FlushModeType.COMMIT : 트랜젝션을 커밋할 때만 플러시하고 쿼리를 실행할 때는 플러시 안함(커밋 시에만 1번 플러시)
  • FlushModeType.AUTO : 쿼리와 커밋할 때 총 4번 플러시

출처

https://product.kyobobook.co.kr/detail/S000000935744

 

자바 ORM 표준 JPA 프로그래밍 | 김영한 - 교보문고

자바 ORM 표준 JPA 프로그래밍 | 자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA

product.kyobobook.co.kr