[Querydsl] 01. 소개 및 프로젝트 설정
Spring Data JPA 에서는 복잡한 쿼리 작성시 @Query 어노테이션을 이용하여 직접 문자열로 쿼리 작성 하였으며
동적 쿼리 작성시 JPA Specification 기능을 이용하여 작성 해야 하나 난이도도 있고 조건에 따른 메소드를 계속적으로 만들어야 한다.
이런 복잡한 쿼리나 동적 쿼리를 쉽게 작성할 수 있는것이 바로 QueryDSL 이며 다른 장점으로는 자바 코드이기에 문법 오류를 컴파일 시점에서 알 수 있다.
이제 실제로 장점을 차근차근 이용해보면서 알아보도록 하자!
우선 프로젝트를 생성해보자!
해당 사이트로 들어가 프로젝트를 생성한다.
위와 같이 선택하고 Dependncies의 ADD를 눌러 필요한 라이브러리를 추가하고 빨간 박스를 클릭하여 프로젝트를 생성한다.
이제 IDE 툴을 통해 해당 프로젝트를 열어보자!
이제 정상 동작하는지 확인을 위해 테스트 코드를 실행 시켜 정상 동작을 하는지 확인 한다.
그리고 추가로 controller 하나 만들어서 체크 한번 한다.
@RestController
public class QuerydslController {
@GetMapping("/corin")
public String corin(){
return "corin";
}
}
웹에서 호출 해보면 정상적으로 동작하는지 알 수 있다.
이제 querydsl 설정과 검증을 진행해보자!
build.gradle 에 querydsl 관련 설정을 추가한다.
build.gradle
dependencies {
...
//Querydsl 추가
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}
// clean시에 querydsl 관련 Q클래스 생성 디렉토리에 있는 파일을 삭제 한다.
clean {
delete file('src/main/generated')
}
테스트를 위해 아래와 같이 Entity 를 생성하며
package study.querydsl.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.*;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
@Entity
public class Corin {
@Id @GeneratedValue
private Long id;
}
gradle 을 통해 build 를 진행하면 아래와 같이 QCorin 클래스가 생성되며 이를 querydsl을 작성할 수 있다.
이제 한번 테스트 코드로 간단하게 이용해보자!
package study.querydsl;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import study.querydsl.entity.Corin;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static study.querydsl.entity.QCorin.corin;
@Transactional
@SpringBootTest
class QuerydslApplicationTests {
@PersistenceContext
EntityManager em;
@Test
void contextLoads() {
Corin entity = Corin.builder().build();
em.persist(entity);
JPAQueryFactory query = new JPAQueryFactory(em);
Corin result = query.selectFrom(corin).fetchOne();
assertEquals(result, entity);
assertEquals(entity.getId(), result.getId());
}
}
'query.selecrFrom' 보면 실제 쿼리와 같이 작성하게 된다.
테스트 코드를 돌려보면 정상적으로 동작하는것을 볼 수 있다.
이제 라이브러리를 상세적으로 보면
apt 는 Q 클래스 만드는 친구, jpa 는 실제 querydsl 쿼리 부분을 담고 있다.
그리고 아래와 같이 의존성 있는 라이브러리가 있으며 옆에 설명 부분을 참고한다.
다음 H2 데이터베이스를 설치 한다. (메모리에서 동작하는 h2)
아래에서 안정화 버전이고 현재 설치한 client 버전에 맞는것을 설치한다.
https://h2database.com/html/main.html
이제 압축을 풀고 file 모드로 처음에 DB파일을 만들고 실행 할때 tcp 모드로 실행해야 어플리케이션과 동시 접속이 가능하므로 순서대로 진행해서 DB를 만들어보자
zib 으로 다운받고 zip 을 풀고 아래와 같은 경로로 접속하여 실행한다.
$ cd h2\ 2/
$ ls
bin build.sh service
build.bat docs src
$ cd bin
$ chmod +x h2.sh
$ ./h2.sh
이제 웹 브라우저에 아래 화면이 뜨며 원하는 경로에 DB 파일 경로를 입력하고 connect 누르면
아래와 같이 DB 에 접속 되며
DB 파일이 생성된다.
$ ls | grep db
querydsl.mv.db
이제 tcp 모드로 DB를 접속하여 동시 접속 가능하도록 한다.
이제 DB연결 설정과 로깅 설정 한다.
application.yml
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/Downloads/querydsl
username: admin
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create # drop and create | create-drop 은 application 종료시에도 drop
properties:
hibernate:
# show_sql: true # system.out log (아래 logger[DEBUG].. 로 출력 하니 해당 로그 주석 처리)
format_sql: true # system.out log
use_sql_comments: true # JPQL 실행 쿼리 출력
logging:
level:
org.hibernaate.SQL: debug # logger로 출력
org.hibernate.type: trace # 쿼리 파라미터 ? 에 대한 출력
이제 예제 엔티티를 만들어보고 테스트를 해보도록 하자!
아래와 같은 엔티티 구조를 가질 예정이며
코드로 작성하면 아래와 같다.
package study.querydsl.entity;
import jakarta.persistence.*;
import lombok.*;
@ToString(of = {"id","username","age"})
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
@Getter
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
@JoinColumn(name = "team_id")
@ManyToOne(fetch = FetchType.LAZY)
private Team team;
public Member(String username, int age, Team team) {
this.username = username;
this.age = age;
if(team != null){
this.team = team;
}
}
public void changeTeam(Team team){
this.team = team;
team.getMembers().add(this);
}
}
ㅇㅇㅇ
package study.querydsl.entity;
import jakarta.persistence.*;
import lombok.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@AllArgsConstructor
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "team_id")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
public Team(String name) {
this.name = name;
}
}
이제 테스트 코드를 돌려 데이터를 넣고 확인하면
package study.querydsl;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import study.querydsl.entity.Corin;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static study.querydsl.entity.QCorin.corin;
@Transactional
@SpringBootTest
class QuerydslApplicationTests {
@PersistenceContext
EntityManager em;
@Test
void contextLoads() {
Corin entity = Corin.builder().build();
em.persist(entity);
JPAQueryFactory query = new JPAQueryFactory(em);
Corin result = query.selectFrom(corin).fetchOne();
assertEquals(result, entity);
assertEquals(entity.getId(), result.getId());
}
}
정상적으로 데이터가 넣어 진것을 볼 수 있다.
이제 다음 시간에는 해당 예제 데이터를 이용하여 querydsl 기본 문법을 익혀보자!
끝!