[Querydsl] Querydsl ์ด๋?
by rlaehddnd0422QueryDsl ์ด๋?
Querydsl์ ์ ์ ํ์ ์ ์ด์ฉํด์ SQL๊ณผ ๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ ์๋๋ก ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋๋ค.
Querydsl์ ์ฟผ๋ฆฌ๋ฅผ type-safeํ๊ฒ ๊ฐ๋ฐํ ์ ์๊ฒ ์ง์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ฃผ๋ก JPA Query ( JPQL )์์ ์ฌ์ฉํฉ๋๋ค.
DSL์ Domain Specific Language๋ก ํน์ ํ ํ ๋ฉ์ธ์ ์ด์ ์ ๋ง์ถ ์ ํ์ ์ธ ํํ๋ ฅ์ ๊ฐ์ง ์ปดํจํฐ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ก ๋จ์ํ๊ณ , ๊ฐ๊ฒฐํฉ๋๋ค.
์ด DSL์ ์ฟผ๋ฆฌ์ ์ ์ฉ์์ผ ์ฟผ๋ฆฌ์ ํนํ๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ก ์ ๊ณตํ ๊ฒ์ด QueryDSL์ ๋๋ค.
๊ธฐ์กด ๋ฐฉ์์๋ ์ด๋ค ๋ฌธ์ ๊ฐ ์์์๊น?
- Query๋ฅผ ์ง์ ์์ฑํด์ผ ํ๋ SQL Mapper ๋ฐฉ์์ด๋ JPA์์ JPQL์ ์ฌ์ฉํด Query๊ฐ ์๋ชป ์์ฑ๋๋ ๊ฒฝ์ฐ ์ปดํ์ผ ์์ ์์ ์ฒดํฌ๊ฐ ๋ถ๊ฐ๋ฅํ๊ณ ์ค์ง ๋ฐํ์ ์์ ์์ ์ฒดํฌ๋ฅผ ํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์๊ฐ ์ค๋ฅ๋ฅผ ์ฐพ๋๋ฐ ์ด๋ ค์์ด ์์์ต๋๋ค. ์ด๋ฐ ๋ฌธ์ ๋ 'type-safe ํ์ง ์๋ค'๊ณ ๋งํฉ๋๋ค.
'type-safe ํ๋ค' -> ์ปดํ์ผ ์์ ์์ ๋ฌธ์ ๋ฅผ ์ก์ ์ ์๋ค.
- Querydsl์ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ๋ฅผ ๋ฉ์๋๋ก ์ ์ดํด์ ์ปดํ์ผ ์์ ์์ ์ฟผ๋ฆฌ์ ์ค๋ฅ๋ฅผ ์ก์์ค ์ ์์ต๋๋ค. ์์ ์ดํด๋ณธ Spring Data JPA์๋ ( ๋์ ์ธ ์ฟผ๋ฆฌ์ ๋ํ ) ์กฐํ์์ ์ฝ์ ์ด ์์์ต๋๋ค.
Querydsl๋ก ๋ณต์กํ ์กฐํ ๊ธฐ๋ฅ์ ๋ณด์ํ๊ณ ๊ทธ ์ธ ๋จ์ํ ๊ฒฝ์ฐ๋ Spring Data JPA๋ฅผ ์ฌ์ฉํฉ์๋ค.
QueryDSL - JPA ๋์
Querydsl์ @Entity ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ๋๋ฉ์ธ์ ์ฝ์ด Query Domain์ ์์ฑํด์ค๋๋ค. (ex) Item -> QItem, Member - > QMember)
JPAQueryFactory query = new JPAQueryFactory (entityManager);
QMember m = QMember.member;
List<Member> list = query.select(m)
.from(m)
.where(m.age.between(20, 40).and(m.name.like("๊น%")))
.orderBy(m.age.desc()) .limit(3)
.fetch(m);
EntityManager๋ฅผ ์ฃผ์ ๋ฐ์ JPAQueryFactory ๊ฐ์ฒด๋ฅผ ํ๋ ๋ง๋ค๊ณ , ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ํตํด ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
๋ฉ์๋๋ฅผ ํตํด์ ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ค๊ฒ ๋๋ฉด type-safeํ ์ด์ ์ ์ป์ต๋๋ค. (ex) ๋ฉ์๋์ ์ด๋ฆ์ ์๋ชป ์์ฑํ๋ ๊ฒฝ์ฐ ์ปดํ์ผ ์์ ์์ ์๋ฌ๋ฅผ ์ก์์ค๋๋ค)
- fetch() : ๋ชฉ๋ก ์กฐํ
- fetchOne() : ๋จ๊ฑด ์กฐํ
์์ฑ๋ ์ฟผ๋ฆฌ
select id, age, name
from MEMBER
where age between 20 and 40 and name like '๊น%'
order by age desc
limit 3
๊ธฐ๋ฅ
- from
- innerJoin, join, leftjoin, fullJoin, on
- where (and,or,allOf,anyOf)
- groupBy
- having
- orderBy(desc,asc)
- limit, offset, restrict
Querydsl ์ค์
dependencies
{
// Querydsl ์ถ๊ฐ
implementation 'com.querydsl:querydsl-jpa'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
//Querydsl ์ถ๊ฐ, ์๋ ์์ฑ๋ Qํด๋์ค gradle clean์ผ๋ก ์ ๊ฑฐ
}
clean {
delete file('src/main/generated')
}
Q ํ์ผ ์์ฑ ํ์ธ
1. Gradle -> Tasks -> build -> clean
2. Gradle -> Tasks -> other -> compileJava
build -> generated - > sources -> annotationProcessor -> java/main ํ์ ํ์ธ
+ ์ฐธ๊ณ : Qํ์ ์ ์ปดํ์ผ ์์ ์ ์๋ ์์ฑ๋๋ฏ๋ก ๋ฒ์ ๊ด๋ฆฌ(GIT)์ ํฌํจํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค.
Querydsl ์ ์ฉ
@Repository
@Transactional
public class JpaItemRepositoryV3 implements ItemRepository {
private final EntityManager em;
private final JPAQueryFactory query;
public JpaItemRepositoryV3(EntityManager em)
{
this.em = em;
this.query = new JPAQueryFactory(em);
}
...
- Querydsl์ ์ฌ์ฉํ๋ ค๋ฉด JPAQueryFactory๊ฐ ํ์ํฉ๋๋ค. JPAQueryFactory๋ JPA ์ฟผ๋ฆฌ์ธ JPQL์ ๋ง๋ค๊ธฐ ๋๋ฌธ์ EntityManager๊ฐ ํ์ํฉ๋๋ค.
- ๋ฌผ๋ก JPAQueryFactory๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํด์ ์ฌ์ฉํด๋ ๋ฉ๋๋ค.
@Override
public Item save(Item item) {
em.persist(item);
return item;
}
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
Item findItem = em.find(Item.class,itemId);
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
@Override
public Optional<Item> findById(Long id) {
Item item = em.find(Item.class, id);
return Optional.ofNullable(item);
}
- save(), update(), findById() ๊ฐ์ ๊ธฐ๋ณธ ๊ธฐ๋ฅ๋ค์ JPA๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ๊ธฐ๋ฅ ์ฌ์ฉ
Querydsl์ ์ ์ฉํด ๋์ ์ฟผ๋ฆฌ ๋ฌธ์ ํด๊ฒฐ
public List<Item> findAllOld(ItemSearchCond cond)
{
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
QItem item = QItem.item;
BooleanBuilder builder = new BooleanBuilder();
if(StringUtils.hasText(itemName))
{
builder.and(item.itemName.like('%'+itemName+'%'));
}
if(maxPrice!=null)
{
builder.and(item.price.loe(maxPrice));
}
List<Item> results = query.select(item)
.from(item)
.where(builder)
.fetch();
return results;
}
- BooleanBuilder๋ฅผ ์ฌ์ฉํด์ ์ํ๋ where์กฐ๊ฑด๋ค์ ๋ฃ์ด์ค๋๋ค.
๋ ๊น๋ํ๊ฒ ๋ฆฌํํ ๋ง
@Override
public List<Item> findAll(ItemSearchCond cond)
{
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
return query.select(item)
.from(item)
.where(likeItemName(itemName), maxPrice(maxPrice))
.fetch();
}
- 1) Qitem static import -> item
- Querydsl์์ where(A,B)์ ๋ค์ํ ์กฐ๊ฑด๋ค์ ์ง์ ๋ฃ์ ์ ์๋๋ฐ, ์ด๋ ๊ฒ ๋ฃ์ผ๋ฉด and๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค. ์กฐ๊ฑด์ด null์ธ ๊ฒฝ์ฐ ํด๋น ์กฐ๊ฑด ๋ฌด์
+ config ์ค์
@Configuration
@RequiredArgsConstructor
public class QuerydslConfig {
private final EntityManager em;
@Bean
public ItemService itemService() {
return new ItemServiceV1(itemRepository());
}
@Bean
public ItemRepository itemRepository() {
return new JpaItemRepositoryV3(em);
}
}
<์ ๋ฆฌ>
- Querydsl์ ์ฌ์ฉํด ๋์ ์ฟผ๋ฆฌ๋ฅผ ๊น๋ํ๊ฒ ์ฒ๋ฆฌํด๋ณด์์ต๋๋ค.
- Querydsl์ ์ฌ์ฉํ๋ฉด type-safeํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์ ์ ์ฅ์์๋ ์ค๋ฅ๋ฅผ ์ฐพ๊ธฐ ์ฝ์ต๋๋ค.
- where๋ฌธ ๋ด์ ๋ฉ์๋๋ก ์กฐ๊ฑด์ ๋ง๋ค์๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๋์ ์ฟผ๋ฆฌ์์๋ ์ฌ์ฌ์ฉ์ ์ฌ์ง๊ฐ ์์ต๋๋ค.
<์ฐธ๊ณ ์๋ฃ>
'๐ Backend > DB Access' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํธ๋์ญ์ AOP @Transactional์ ์ต์ (0) | 2023.04.20 |
---|---|
ํธ๋์ญ์ AOP @Transactional ์ฌ์ฉ ์ ์ฃผ์์ฌํญ (1) | 2023.04.20 |
[Spring Data JPA] ์คํ๋ง ๋ฐ์ดํฐ JPA (0) | 2023.04.17 |
[JPA] JPA(Java Persistent API) (0) | 2023.04.17 |
TestCode์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ ์ฐ๋ (1) | 2023.04.15 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422