혼자공부중
공부하는 블로그
혼자공부중
전체 방문자
오늘
어제
  • 분류 전체보기 (111)
    • 자격증 (49)
      • 정보처리기사 실기 (49)
    • JAVA (18)
    • DB (0)
    • 알고리즘 문제 풀이 (11)
      • 프로그래머스 (11)
    • Front (0)
      • HTML (0)
      • CSS (0)
      • Javascript (0)
    • 패스트캠퍼스 강의 (33)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 상속
  • 변수
  • SQLD
  • 데이터모델
  • 데이터베이스
  • 배열
  • DBMS
  • 수제비
  • 패스트캠퍼스 #포트폴리오 #직장인자기계발 #환급챌린지 #포트폴리오챌린지 #패스트캠퍼스후기 #초격차패키지 #오공완
  • 2022정보처리기사
  • 메소드
  • 애플리케이션테스트
  • Java
  • 2022정보처리기사필기
  • UI
  • 자바
  • 반복문
  • 알고리즘
  • 코딩테스트
  • 객체지향
  • 관계형데이터베이스
  • 시나공
  • 정보처리기사 실기
  • 정보처리기사 필기 정리
  • 정보처리기사 필기
  • 2022정보처리기사실기
  • 인터페이스
  • 정보처리기사
  • 정보처리기사 실기 정리
  • 프로그래머스

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
혼자공부중

공부하는 블로그

[20일차] 50일 포트폴리오 챌린지
패스트캠퍼스 강의

[20일차] 50일 포트폴리오 챌린지

2023. 8. 27. 14:37
본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

https://bit.ly/43z0P6S 

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr



QueryDSL JPA

QueryDSL JPA는

  1. SQL, JPQL을 코드로 작성할 수 있도록 해주는 빌더 API이고
  2. Entity 클래스와 매핑되는 QClass라는 객체를 사용해서 쿼리를 실행한다

QClass란?

QueryDSL 은 컴파일 단계에서 엔티티를 기반으로 QClass 를 생성하는데 JPAAnnotationProcessor 가 컴파일 시점에 작동해서 @Entity 등등의 어노테이션을 찾아 해당 파일들을 분석해서 QClass 를 만든다.

QClass 는 Entity 와 형태가 똑같은 Static Class 이다. QueryDSL 은 쿼리를 작성할 때 QClass 를 기반으로 쿼리를 실행한다.

JPQL이란?

JPA 에서 지원하는 다양한 쿼리 방법 중 가장 단순한 조회 방법으로, SQL 의 경우에는 DB 테이블을 대상으로 쿼리를 질의하지만, JPQL 은 엔티티 객체를 대상으로 쿼리를 질의한다.

EX)

String jpql = “select m From Member m where m.name like ‘%hello%’”;
List<Member> result = em.createQuery(jpql, Member.class).getResultList();

(SQL 로 변환시) select * from members where name like ‘%hello%’;

위 설명만 봤을 때에는 굳이 QueryDSL JPA 를 사용해야 하나 ? 그냥 JPQL 을 사용하면 안되나 ? 라는 생각이 들수 있다.

하지만, JPQL 에는 문제점이 존재한다.

JPQL의 문제점

  1. 쿼리를 여전히 문자열로 입력한다. ⇒ 오타가 발생하거나 관리하는데 있어서 어려움이 따르고, type-check 가 불가능하다
  2. 컴파일 단계에서 오류를 확인할 수 없고, 런타임에서 해당 쿼리가 실행되어야 오류를 발견할 수 있다. ⇒ 테스트 코드를 짜면 불안을 덜 수 있긴 하지만, 실제 프로그램을 운영하면서 오류가 발생할 수도 있다는 부담이 너무 커진다.

QueryDSL JPA 는 JPQL 이 가지고 있는 문제점들을 해결해준다.

QueryDSL JPA를 사용해야 하는 이유

  1. 쿼리를 여전히 문자열로 입력하기 때문에 오타가 발생하거나 관리하기 어렵다. ⇒ QueryDSL 은 쿼리를 문자열로서가 아니라 코드를 통해서 작성하기 때문에 오타가 날 확률이 적어지고, 객체 지향적으로 개발할 수 있다.
  2. 컴파일 단계에서 오류를 확인할 수 없고, 런타임 시 해당 쿼리가 실행되어야지만 오류를 확인할 수 있다. ⇒ QueryDSL 은 코드로서 작성하기 때문에 컴파일 단계에서도 오류를 빠르게 발견할 수 있다.

예를 들어서

회원(member) 와 포인트(point) 를 조인해서 가져와야 할 때

JPQL 의 경우에는

String jpql = "select * from Member m join Point p on p.member_id = m.id"
List<Member> result = em.createQuery(jpql, Member.class).getResultList();

이런식으로 쿼리를 작성해야 하지만,

QueryDSL 을 사용했을 때에는

return jpaQueryFactory
.from(member)
.join(member.point, point)
.fetch();

이런 식으로 코드를 사용해서 나타낼 수 있다.

오타가 나더라도 컴파일 단계에서 오류를 확인 할 수 있고, 코드로서 작성하기 때문에 더욱 객체 지향적으로 개발할 수 있다.

이러한 이유로 spring 에서 JPA 를 사용할 때 QueryDSL JPA 를 보통 함께 사용한다.

build.gradle에 QueryDSL 세팅

dependencies {
	...
	implementation 'com.querydsl:querydsl-jpa'
	implementation 'com.querydsl:querydsl-apt'

	annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
	annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
	annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
}

def querydslSrcDir = 'src/main/generated'
sourceSets {
  main {
    java {
      srcDirs += [ querydslSrcDir ]
    }
  }
}

tasks.withType(JavaCompile) {
	options.generatedSourceOutputDirectory = file(querydslSrcDir)
}

clean {
  delete file(querydslSrcDir)
}

dependencies

implementation 'com.querydsl:querydsl-jpa'
implementation 'com.querydsl:querydsl-apt'

annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'

implementation 'com.querydsl:querydsl-jpa'

→ QueryDSL 을 사용하기 위한 라이브러리

→ QuerydslRepositorySupport, QuerydslPredicateExecutor 등 QueryDSL 내부 클래스는 사용 가능하지만, 실제로 쿼리를 위해 사용되는 QClass 는 생성되지 않는다.


implementation 'com.querydsl:querydsl-apt'

→ QClass 를 생성하기 위한 라이브러리


annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"

→ QueryDSL JPA 의 경우에는 Q 클래스를 활용해서 동작하는데 @Entity 어노테이션을 선언한 클래스를 탐색하고, Q 클래스를 생성한다.

Q 클래스를 생성하는 방법에는 크게 두가지로 나뉜다.

  1. com.ewerk.gradle.plugins.querydsl
    • 2018년 이후 업데이트 된 적이 없다.
    • gradle 버전이 계속적으로 업데이트되면서 해당 플러그인 외 여러가지 설정해줘야 할 것 들이 많다.
  2. annotationProcessor

이번에는 ewerk 관련 단점들 때문에 두번째 방식인 annotationProcessor 를 사용한다.


annotationProcessor 'jakarta.persistence:jakarta.persistence-api'

annotationProcessor 'jakarta.annotation:jakarta.annotation-api'

이클립스 재단으로 자바가 이관되면서 java → jakarta 로 이름이 변경되었다.

Q 파일을 찾지 못해서 발생하는 오류인 java.lang.NoClassDefFoundError (javax.annotation.Entity / javax.annotation.Generated) 에러 발생 대응을 위한 코드 이다.

sourceSets

def querydslSrcDir = 'src/main/generated'
sourceSets {
  main {
    java {
      srcDirs += [ querydslSrcDir ]
    }
  }
}

gradle build 시 QClass 소스도 함께 build 하기 위해서 sourceSets 에 해당 위치를 추가해준다.

tasks.withType

tasks.withType(JavaCompile) {
	options.generatedSourceOutputDirectory = file(querydslSrcDir)
}

annotationProcessorGeneratedSourcesDirectory 를 사용할 수도 있는데,

Gradle 공식 문서에 해당 기능은 deprecated 되었고, 추후 major version 에선 삭제할 것이라고 소개하고 있기 때문에 generatedSourceOutputDirectory 를 사용한다.

generatedSourceOutputDirectory 는 annotation processors 에서 생성한 소스 파일을 저장할 디렉토리를 지정 해준다. (Gradle 공식문서 → CompileOptions - Gradle DSL Version 7.5.1 )

이 코드를 통해 위에서 선언한 querydslSrcDir 변수의 src/main/generated 에다가 annotation processors 가 만든 QClass 들을 저장해준다.

clean

clean {
	// clean 실행 시 생성된 QClass 삭제
	delete file(querydslSrcDir)
}

build clean 시에 생성되었던 QClass 를 모두 삭제 (querydslSrcDir = src/main/generated)

저작자표시 변경금지 (새창열림)

'패스트캠퍼스 강의' 카테고리의 다른 글

[22일차] 50일 포트폴리오 챌린지  (0) 2023.08.29
[21일차] 50일 포트폴리오 챌린지  (0) 2023.08.28
[19일차] 50일 포트폴리오 챌린지  (0) 2023.08.26
[18일차] 50일 포트폴리오 챌린지  (0) 2023.08.25
[17일차] 50일 포트폴리오 챌린지  (0) 2023.08.24
    '패스트캠퍼스 강의' 카테고리의 다른 글
    • [22일차] 50일 포트폴리오 챌린지
    • [21일차] 50일 포트폴리오 챌린지
    • [19일차] 50일 포트폴리오 챌린지
    • [18일차] 50일 포트폴리오 챌린지
    혼자공부중
    혼자공부중
    대단한 목적보다는 혼자 공부하는 것에 의미를 두려고 합니다.

    티스토리툴바