๐ ์ฌ์ฉ ๊ณ๊ธฐ
๋ฐ์ดํฐ ๊ฒ์ ์ฑ๋ฅ ๊ฐ์ ์ ํด๋ณด๋ ํ๋ก์ ํธ์์ ๊ฒ์ ์ํ์ ๋ฐ๋ผ ๋ค๋ฅธ JPQL๋ฌธ์ ์์ฑํ ํ์๊ฐ ์์ด QueryDSL์ ์ ์ฉํ๊ฒ ๋์๋ค.
๐QueryDSL์ด๋?
JPQL๋ฌธ์ ๋ฌธ์์ด์ด ์๋ ์๋ฐ ์ฝ๋๋ก ์์ฑํ ์ ์๋๋ก ๋น๋ ์ญํ ์ ํ๋ ์คํ ์์ค
๐QueryDSL ํน์ง
- ์ฟผ๋ฆฌ๋ฅผ ์ฝ๋๋ก ์์ฑํด ์ปดํ์ผ ์ ์ค๋ฅ ๋ฐ๊ฒฌ์ด ๊ฐ๋ฅํ๋ค.
- ์ฝ๋ ๊ธฐ๋ฐ์ ๋จ์ํ์ฌ ์ฌ์ฉ์ด ์ฝ๊ณ ๊ฐ๋ ์ฑ์ด ์ข์
- ์๋ ์์ฑ ๋ฑ IDE์ ๋์ ๊ฐ๋ฅ
- ๋์ ์ฟผ๋ฆฌ ๊ตฌํ ๊ฐ๋ฅ
๐์ ์ฉ ๋ฐฉ๋ฒ
- build.gradle
buildscript { // gradle๋ก task๋ฅผ ์ํํ ๋์ ์ฌ์ฉ๋๋ ์ค์
ext { // build.gradle์์ ์ฌ์ฉํ๋ ์ ์ญ ๋ณ์ ์ค์
queryDslVersion = "5.0.0" // ๋ณ์ queryDslVersion์ 5.0.0 ๋์
}
}
plugins { // gradle task์ ์งํฉ
//....//
id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10' // querydsl plugin ์ ์ฉ
}
dependencies {
//....//
// querydsl ์์กด์ฑ ์ถ๊ฐ
// buildscript์์ ์ ์ฉํ ๋ณ์ queryDslVersion์ด ์ฌ๊ธฐ์ ์ ์ฉ
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
}
// ๋ณ์ ์ ์ธ, ๊ทธ ๋ณ์์ ํด๋ ๊ฒฝ๋ก ์ ์ฅ
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
jpa = true // JPA ์ฌ์ฉ์ฌ๋ถ ์ค์
querydslSourcesDir = querydslDir // ์ฌ์ฉํ ๊ฒฝ๋ก ์ค์
}
sourceSets { // build์ ์ฌ์ฉํ sourceSet ์ถ๊ฐ
main.java.srcDir querydslDir
}
compileQuerydsl { // queryDSL ์ปดํ์ผ์ ์ฌ์ฉํ ์ต์
์ค์
options.annotationProcessorPath = configurations.querydsl
}
configurations { // build ์ต์
compileOnly {
extendsFrom annotationProcessor
}
// querydsl์ด compileClasspath๋ฅผ ์์ํ๋๋ก ์ค์
querydsl.extendsFrom compileClasspath
}
- config
@Configuration
public class QuerydslConfig {
@PersistenceContext
// @PersistenceContext๋ก ์ฃผ์
๋ฐ์ Entity Manager์ Proxy๋ก ๊ฐ์ธ์ง๋ค.
// EntityManager ํธ์ถ์ ๋ง๋ค Proxy๋ฅผ ํตํด EntityManager์ ์์ฑํ์ฌ Thread-Safe๋ฅผ ๋ณด์ฅ
private EntityManager entityManager;
@Bean
// JPAQuery๋ฅผ ์์ฑํด์ฃผ๋ factoryํด๋์ค
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
- Q-Class
QueryDSL์์๋ Entity๋ก ์ค์ ๋ ํด๋์ค์ Q๋ชจ๋ธ์ ์ฟผ๋ฆฌ ํ์ ํด๋์ค๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํ๊ณ ๋ฉํ๋ฐ์ดํฐ๋ก ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ๋ฉ์๋ ๊ธฐ๋ฐ์ผ๋ก ์์ฑํ๋ค.
์์ฑํ๋ ๋ฐฉ๋ฒ์ Tool Window Bar (์ฌ์ด๋์ ๋ณด์ด๋ ๋ฉ๋ด๋ช )์์ Gradle > other > compileJava ํด๋ฆญ
๐ QueryDSL ๊ตฌํ ๋ฐฉ๋ฒ (์ด 3๊ฐ์ง)
- ๋ฐฉ๋ฒ 1 ) QuerydslRepositorySupport๋ฅผ ์์ ๋ฐ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- ๊ตฌํ์ฝ๋
- JpaRepository๋ฅผ ์์ ๋ฐ๋ ProductRepository ์ธํฐํ์ด์ค ํ๋
import com.example.showmethemany.domain.Products; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductRepository extends JpaRepository<Products, Long> { }
- QuerydslRepositorySupport๋ฅผ ์์ํ๊ณ Super์์ฑ์์ Entity๋ฅผ ์ง์ ํด์ ๋ฃ์ ํด๋์ค ํ๋(ProductRepositorySupport)
import com.example.showmethemany.domain.Products; import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; import org.springframework.stereotype.Repository; import static com.example.showmethemany.domain.QProducts.products; @Repository public class ProductRepositorySupport extends QuerydslRepositorySupport { private final JPAQueryFactory queryFactory; public ProductRepositorySupport(JPAQueryFactory queryFactory) { super(Products.class); this.queryFactory = queryFactory; } public Products findByProductId (Long productId) { return queryFactory.select(products) .from(products) .where(products.id.eq(productId)) .fetchOne(); } }
- JpaRepository๋ฅผ ์์ ๋ฐ๋ ProductRepository ์ธํฐํ์ด์ค ํ๋
- ํ
์คํธ์ฝ๋
import com.example.showmethemany.domain.Products; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest class ProductRepositorySupportTest { @Autowired ProductRepository productRepository; @Autowired ProductRepositorySupport productRepositorySupport; @Test @DisplayName("QueryDSL Support ์์ ๊ตฌํ ๋ฐฉ์ ํ ์คํธ") void findByProductId() { //given Long productId = 1L; //when Products products = productRepositorySupport.findByProductId(productId); //then assertEquals(26910, products.getPrice()); } }
- ๊ฒฐ๊ณผ
๊ทธ๋ฌ๋ ์ด ๊ตฌํ ๋ฐฉ๋ฒ์ ๋ฌธ์ ์ ์
QuerydslRepositorySupport(์ฝ๋์ ProductRepositorySupport)์ JpaRepository(์ฝ๋์ ProductRepository)๊ฐ ๊ธฐ๋ฅ์ ๋๋ ๊ฐ์ ธ ํญ์ 2๊ฐ๋ฅผ ์์กด์ฑ์ผ๋ก ๋ฐ์์ผ ํ๋ ๋ฌธ์ ๊ฐ ์๋ค
- ๊ตฌํ์ฝ๋
- ๋ฐฉ๋ฒ 2 ) CustomRepository ์์๊ณผ ๊ตฌํ์ด ํ์ํ ๋ฐฉ๋ฒ
- ๊ตฌํ์ฝ๋
- CustomRepository ์ธํฐํ์ด์ค ํ๋
import com.example.showmethemany.domain.Product public interface ProductRepositoryCustom { Products findByProductId (Long productId); }
- CustomRepository ์ ๊ตฌํ์ฒด ํ๋
import com.example.showmethemany.domain.Products; import com.querydsl.jpa.impl.JPAQueryFactory; import javax.persistence.EntityManager; import static com.example.showmethemany.domain.QProducts.products; public class ProductRepositoryImpl implements ProductRepositoryCustom { private final JPAQueryFactory queryFactory; public ProductRepositoryImpl(EntityManager em) { this.queryFactory = new JPAQueryFactory(em); } @Override public Products findByProductId(Long productId) { return queryFactory.select(products) .from(products) .where(products.id.eq(productId)) .fetchOne(); } }
- JpaRepository ์ CustomRepository๋ฅผ ์์ํจ์ผ๋ก์จ CustomRepositoryImpl๋ ์ฌ์ฉ ๊ฐ๋ฅ
import com.example.showmethemany.domain.Products; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductRepository extends JpaRepository<Products, Long>, ProductRepositoryCustom { }
- CustomRepository ์ธํฐํ์ด์ค ํ๋
- ํ
์คํธ์ฝ๋
@SpringBootTest class ProductRepositoryTest { @Autowired ProductRepository productRepository; @Test @DisplayName("QueryDSL CustomRepository ์์ ๋ฐฉ์ ํ ์คํธ") void findByProductId() { //given Long productId = 1L; //when Products products = productRepository.findByProductId(productId); //then assertEquals(26910, products.getPrice()); } }
- ๊ฒฐ๊ณผ
๊ทธ๋ฌ๋ ์ด ๊ตฌํ ๋ฐฉ๋ฒ์ ๋ฌธ์ ์ ์
ํ๋์ Repository๋น interfaceํ๋์ Implํ๋ ์ด 2๊ฐ๋ฅผ ๋ ๋ง๋ค์ด์ค์ผ ํ๋ค. (์ด 3๊ฐ)
- ๊ตฌํ์ฝ๋
- ๋ฐฉ๋ฒ 3 ) ์์๊ณผ ๊ตฌํ ์์ด ๊ฐ๋ฅํ ๋ฐฉ๋ฒ
- ๊ตฌํ์ฝ๋
- JPAQueryFactory๋ฅผ ์ฃผ์
๋ฐ์ Repository class ํ๋
JPAQueryFactory๋ง ์ฃผ์ ๋ฐ์ผ๋ฉด QueryDSL์ ์ฌ์ฉํ ์ ์๊ณ ํน์ Entity ์ง์ ํ์ง ์์๋ ์ฌ๋ฌ Entity๋ฅผ ๋์์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
import com.example.showmethemany.domain.Products; import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.stereotype.Repository; import static com.example.showmethemany.domain.QProducts.products; @Repository public class ProductRepository { private final JPAQueryFactory queryFactory; public ProductRepository(JPAQueryFactory queryFactory) { this.queryFactory = queryFactory; } public Products findByProductId (Long productId) { return queryFactory.select(products) .from(products) .where(products.id.eq(productId)) .fetchOne(); } }
- JPAQueryFactory๋ฅผ ์ฃผ์
๋ฐ์ Repository class ํ๋
- ํ
์คํธ์ฝ๋
@SpringBootTest class ProductRepositoryTest { @Autowired private ProductRepository productRepository; @Test @DisplayName("QueryDSL ์์/๊ตฌํ ์๋ ๋ฐฉ์ ํ ์คํธ") void findById() { //given Long productId = 1L; //when Products products = productRepository.findByProductId(productId); //then assertEquals(26910, products.getPrice()); } }
- ๊ฒฐ๊ณผ
์ด ๊ตฌํ ๋ฐฉ๋ฒ์ ๋ค๋ฅธ ๊ฒฝ์ฐ๋ณด๋ค ๋ถ๋ด์ด ๋๋๋ค๋ ์ฅ์ ์ ์์ง๋ง ๊ธฐ๋ณธ JpaRepository์๋ ๋ณ๊ฐ๊ฐ ๋๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด Repository์ ๋ฉ์๋๋ฅผ ์ฐธ์กฐํ ์ ์๊ฒ ๋๋ค. QueryDSL๋ง ์ฌ์ฉํ๊ฒ ๋๋ฉด JPA๋ก ๊ฐ๋จํ ์ฌ์ฉํ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํด ์ค์ผ ํ๋ค๋ ๋จ์ ์ด ์๋ค. ๊ทธ๋์ ํ๋ก์ ํธ์๋ QueryDSL๊ณผ Spring Data JPA๋ฅผ ๊ฐ์ด ์ฐ๋ ๋ฐฉํฅ์ผ๋ก ์งํํ๋ค.
- ๊ตฌํ์ฝ๋
'Programming > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ฐ์ฒด ์งํฅ ์ค๊ณ์ ์คํ๋ง (0) | 2023.03.16 |
---|---|
WebRTC ์๊ทธ๋๋ง ์๋ฒ (Spring Boot๋ก ๊ตฌํ) (1) | 2023.01.12 |
Query DSL (0) | 2022.12.15 |
์คํ๋ง ๋ถํธ(Spring Boot) ๋ค์ด ๊ทธ๋ ์ด๋ (0) | 2022.12.07 |
ORM / JPA / Hibernate / Spring Data JPA (0) | 2022.12.05 |