본문 바로가기
개발자 전향 프로젝트

[JAVA] JPA 활용법 -1 (QueryDSL 적용해보기)

by 샘오리 2022. 10. 24.
728x90
반응형

QueryDSL이란?

Spring Boot Data JPA 는 쿼리문을 직접 짜지 않아도 함수명만 알맞게 적어주면

쿼리를 자동으로 짜주는 ORM으로 유명한데 사실상 조금만 복잡하고 동적인 쿼리를 짜려고만 해도

JPQL등을 통해 쿼리를 직접 짜야하는 불상사가 발생하고 만다.

 

이러한 불편함을 줄여주고자 자바만 알아도 쿼리를 대신 짜주는 프레임워크가 있는데

이를 QueryDSL 이라고 부른다.

 

쿼리가 아니라 자바 기반이라서 컴파일 시점에 오류 발견이 가능하고, 자동완성도 지원하여 실무에서도 많이 사용되고 있다. 필자도 QueryDSL을 사용해보고 싶었지만 진입장벽이 있는 것 같아서 망설이다가 블로그에 글을 쓸 핑계로 공부를 해보고 알아낸 내용을 공유해보려고 한다.

 

 


1. 개발환경 맞추기

1-1 generate 해서 인텔리제이로 열기

2. build.gradle에 QueryDSL 프레임워크 적용하기

PROJECT: Gradle

Boot: 2.7.5

JAVA: 17

DBMS: H2 (테스트용)

plugins {
	id 'org.springframework.boot' version '2.7.5'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
	id 'java'
}

group = 'com.QueryDSL'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'

	implementation group: 'com.querydsl', name: 'querydsl-jpa', version: '5.0.0'
	implementation group: 'com.querydsl', name: 'querydsl-core', version: '5.0.0'
	implementation group: 'com.querydsl', name: 'querydsl-apt', version: '5.0.0'

	annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jpa"
	annotationProcessor("jakarta.persistence:jakarta.persistence-api")
	annotationProcessor("jakarta.annotation:jakarta.annotation-api")

// QueryDSL
	sourceSets {
		main {
			java {
				srcDirs = ["$projectDir/src/main/java"]
			}
		}
	}
}

tasks.named('test') {
	useJUnitPlatform()
}

3. QueryDSL Config 파일 생성하기

package com.QueryDSL.Drill;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Configuration
public class QuerydslConfiguration {

    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }
}

4. 일반 도메인=엔티티 생성하기

package com.QueryDSL.Drill.entity;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Employees {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String address;

    @Builder
    public Employees(String name, String address) {
        this.name = name;
        this.address = address;
    }

    @Override
    public String toString() {
        return '\n'+"직원 명단 {" + '\n'+
                "  순서 = " + id + '\n'+
                ", 이름 = " + name + '\n'+'\''+
                ", 주소 = " + address + '\n'+ '\'' +
                '}';
    }
}

5. QueryDSL 전용 엔티티 생성하기

5-1

보기->도구 창 -> Gradle

5-2

other -> compile.Java 더블클릭

5-3

위 그림처럼 기본 엔티니를 기반으로 쿼리DSL 전용 엔티티가 build->generated 안에 생성됨

클릭해보면 static으로 인스턴스화 되어있는것을 확인 할 수 있음

6. REPOSITORY

6-1 기본 JPA Repository 생성하기

package com.QueryDSL.Drill.repository;

import com.QueryDSL.Drill.entity.Employees;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employees, Long> {
}

6-2 QueryDSL 전용 Repository 생성하기

package com.QueryDSL.Drill.repository;

import com.QueryDSL.Drill.entity.Employees;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

import static com.QueryDSL.Drill.entity.QEmployees.employees;

@RequiredArgsConstructor
@Repository
public class EmployeeRepositorySupport {
    private final JPAQueryFactory queryFactory;

    public List<Employees> findByName(String name) {
        return queryFactory
                .selectFrom(employees)
                .where(employees.name.eq(name))
                .fetch();
    }
    public List<Employees> findAll() {
        return queryFactory
                .selectFrom(employees)
                .fetch();
    }
}

6-3

아래 그림처럼 빨간줄이 떠있는 employees 를 static import 하기 (빨간줄에 alt+enter OR 마우스 hover)

7. 테스트 하기

package com.QueryDSL.Drill;

import com.QueryDSL.Drill.entity.Employees;
import com.QueryDSL.Drill.repository.EmployeeRepository;
import com.QueryDSL.Drill.repository.EmployeeRepositorySupport;
import org.junit.After;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class DrillApplicationTests {

		@Autowired
		private EmployeeRepository employeeRepository;

		@Autowired
		private EmployeeRepositorySupport employeeRepositorySupport;

		@After
		public void tearDown() throws Exception {
			employeeRepository.deleteAllInBatch();
		}

		@Test
		public void querydsl_기본_기능_확인() {
			//given
			employeeRepository.save(new Employees("보라돌이", "서울"));
			employeeRepository.save(new Employees("뚜비", "부산"));
			employeeRepository.save(new Employees("나나", "제주도"));

			//when
			List<Employees> selectOne = employeeRepositorySupport.findByName("보라돌이");
			List<Employees> selectAll = employeeRepositorySupport.findAll();
			//then
			System.out.println("--------한명만 조회하기------- " + selectOne);
			System.out.println("--------모두 조회하기-------- " + selectAll);
		}
	}

결과

728x90
반응형