๐Ÿ’ป Language/Java : ์ž๋ฐ”

[Java/JPA] QueryDSL์ด๋ž€?

mxnxeonx 2025. 3. 25. 16:31
728x90
728x90

QueryDSL

QueryDSL์€ Java ๊ธฐ๋ฐ˜์˜ ํƒ€์ž… ์•ˆ์ „(type-safe)ํ•œ SQL ์ฟผ๋ฆฌ ์ƒ์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ JPA, Hibernate ๋“ฑ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜์–ด ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ฝ”๋“œ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค. ๋‹ค์Œ์€ QueryDSL์˜ ์ฃผ์š” ํŠน์ง•๊ณผ ์žฅ์ , ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

 

QueryDSL์€ ์ •์  ํƒ€์ž…์„ ์ด์šฉํ•ด์„œ SQL๊ณผ ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ฃผ๋Š” ์˜คํ”ˆ์†Œ์Šค ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค. Fluent API๋ฅผ ์ด์šฉํ•ด ์ฝ”๋“œ ์ž‘์„ฑ ํ˜•์‹์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

 

QueryDSL์ด ์ ํ•ฉํ•œ ์ƒํ™ฉ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. ๋ณต์žกํ•œ ๊ฒ€์ƒ‰ ์กฐ๊ฑด์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ (ex. ๊ฒŒ์‹œํŒ ํ•„ํ„ฐ, ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ)
  2. ๋™์  ์ฟผ๋ฆฌ๊ฐ€ ์ž์ฃผ ํ•„์š”ํ•œ ๋„๋ฉ”์ธ
  3. SQL ์ฟผ๋ฆฌ๋ฅผ ๋ฌธ์ž์—ด์ด ์•„๋‹Œ ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋กœ ๋‹ค๋ฃจ๊ณ  ์‹ถ์„ ๋•Œ
 

Querydsl - Unified Queries for Java

Unified Queries for Java. Querydsl is compact, safe and easy to learn. <!-- Querydsl Unified Queries for Java Querydsl provides a unified querying layer for multiple backends in Java. Compared to the alternatives Querydsl is more compact, safer and easier

querydsl.com

 

QueryDSL์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  1. ์ฟผ๋ฆฌ๋ฅผ Java ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ฌธ๋ฒ• ์˜ค๋ฅ˜๋ฅผ ์žก์„ ์ˆ˜ ์žˆ๋‹ค.
    • SQL ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ(JPQL, Native Query)๋ณด๋‹ค ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ์ค„์–ด๋“œ๋Š” ์žฅ์ ์ด ์žˆ์Œ.
      → JPQL์€ ์ฟผ๋ฆฌ๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ž‘์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ž˜๋ชป ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์˜คํƒ€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋„ ์ปดํŒŒ์ผ ์‹œ์ ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋‹ค๊ฐ€ ๋Ÿฐํƒ€์ž„ ์ค‘์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹คํ–‰ ์ „์—๋Š” ์ž˜๋ชป๋œ ๋ถ€๋ถ„์„ ํŒŒ์•…ํ•  ์ˆ˜ ์—†๋‹ค.
  2. ๋™์  ์ฟผ๋ฆฌ ์ž‘์„ฑ์ด ์šฉ์ดํ•˜๋‹ค. (Qํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ)
    • IF ์กฐ๊ฑด ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์œ ์—ฐํ•˜๊ฒŒ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋ณต์žกํ•œ ๊ฒ€์ƒ‰ ์กฐ๊ฑด(ex. ์—ฌ๋Ÿฌ ๊ฒ€์ƒ‰ ํ•„ํ„ฐ ์ ์šฉ)์— ์ ํ•ฉํ•˜๋‹ค.
      → JPQL์„ ์ด์šฉํ•ด ๋™์  ์ฟผ๋ฆฌ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ž์—ด์„ ์กฐ๊ฑด์— ๋งž๊ฒŒ ์กฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์ด ๊ฒฝ์šฐ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ณ  ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์น˜๋ช…์ ์ธ ๋‹จ์ ์ด ์กด์žฌํ•œ๋‹ค.
  3. IDE ์ž๋™์™„์„ฑ์„ ์ง€์›ํ•œ๋‹ค.
    • Qํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ํ•„๋“œ๋ช… ์ž๋™์™„์„ฑ์ด ๊ฐ€๋Šฅํ•˜์—ฌ ์ƒ์‚ฐ์„ฑ์ด ํ–ฅ์ƒ๋œ๋‹ค.
  4. SQL-Likeํ•œ ๋ฌธ๋ฒ•์„ Java ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๊ธฐ์— ๋ฌธ๋ฒ•์ด ์ง๊ด€์ ์ด๋‹ค.

 

QueryDSL ์‚ฌ์šฉ ์˜ˆ์‹œ

1. Entity ํด๋ž˜์Šค

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    private String username;
    private int age;
}

 

2. Qํด๋ž˜์Šค ์ƒ์„ฑ

Gradle ๋˜๋Š” Maven์—์„œ annotationProcessor ์„ค์ •์œผ๋กœ Qํด๋ž˜์Šค(QMember) ์ž๋™ ์ƒ์„ฑ

 

Maven์˜ ๊ฒฝ์šฐ, IntelliJ ์šฐ์ธก ๋ฉ”์ด๋ธ ๋„๊ตฌ - Lifecycle - compile์„ ์‹คํ–‰ํ•˜์—ฌ Qํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

Maven - ํ”„๋กœ์ ํŠธ๋ช… - Lifecycle - compile
target - generated-sources - annotations ํ•˜์œ„

 

3-1. ์ •์  ์ฟผ๋ฆฌ ์˜ˆ์‹œ

JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
QMember member = QMember.member;

Member result = queryFactory
    .selectFrom(member)
    .where(member.username.eq("ํ™๊ธธ๋™"))
    .fetchOne();

 

3-2. ๋™์  ์ฟผ๋ฆฌ ์˜ˆ์‹œ

public List<Member> search(String usernameCond, Integer ageCond) {
    return queryFactory
        .selectFrom(member)
        .where(
            usernameEq(usernameCond),
            ageEq(ageCond)
        )
        .fetch();
}

private BooleanExpression usernameEq(String username) {
    return StringUtils.hasText(username) ? member.username.eq(username) : null;
}

private BooleanExpression ageEq(Integer age) {
    return age != null ? member.age.eq(age) : null;
}

 

 

QueryDSL ๋ฉ”์„œ๋“œ ์ข…๋ฅ˜

๋ชฉ์  ๋ฉ”์„œ๋“œ ์„ค๋ช…
SELECT select(), selectFrom() ์กฐํšŒํ•  ์ปฌ๋Ÿผ ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง€์ •
FROM from() ์กฐํšŒํ•  ํ…Œ์ด๋ธ”(Qํƒ€์ž…)์„ ์ง€์ • (selectFrom์€ select + from ๊ฒฐํ•ฉ)
WHERE where() ์กฐ๊ฑด์ ˆ ์„ค์ • (BooleanExpression ๋„ฃ์Œ)
GROUP BY groupBy() ๊ทธ๋ฃนํ•‘
HAVING having() ๊ทธ๋ฃน ์กฐ๊ฑด
ORDER BY orderBy() ์ •๋ ฌ ์กฐ๊ฑด
JOIN join(), leftJoin(), rightJoin() ์กฐ์ธ (inner, left, right ๋“ฑ)
UPDATE update() ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์ˆ˜์ • ์ฟผ๋ฆฌ
DELETE delete() ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์‚ญ์ œ ์ฟผ๋ฆฌ
INSERT insert() SQLQueryFactory ์‚ฌ์šฉ ์‹œ ๊ฐ€๋Šฅ, JPA์—์„œ๋Š” ์ง์ ‘์ ์œผ๋กœ ์ง€์› X
FETCH fetch(), fetchOne(), fetchFirst(), fetchResults() ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ ๋ฉ”์„œ๋“œ

 

WHERE ์กฐ๊ฑด์ ˆ ๋ฉ”์„œ๋“œ (BooleanExpression)

SQL ํ‘œํ˜„ QueryDSL ํ‘œํ˜„ ์„ค๋ช…
= eq() ๊ฐ™์Œ
!= ne() ๋‹ค๋ฆ„
> gt() ํฌ๋‹ค (greater than)
< lt() ์ž‘๋‹ค (less than)
>= goe() ํฌ๊ฑฐ๋‚˜ ๊ฐ™๋‹ค (greater or equal)
<= loe() ์ž‘๊ฑฐ๋‚˜ ๊ฐ™๋‹ค (less or equal)
IN (...) in() ํฌํ•จ๋จ
NOT IN (...) notIn() ํฌํ•จ๋˜์ง€ ์•Š์Œ
LIKE like(), contains(), startsWith() ๋ฌธ์ž์—ด ํฌํ•จ ์—ฌ๋ถ€
IS NULL isNull() null์ธ์ง€ ํ™•์ธ
IS NOT NULL isNotNull() null์ด ์•„๋‹Œ์ง€ ํ™•์ธ
AND, OR .and(), .or() ์กฐ๊ฑด ์กฐํ•ฉ
NOT .not() ๋ถ€์ • ์กฐ๊ฑด
BETWEEN A AND B between() ๋ฒ”์œ„ ์กฐ๊ฑด

 

์˜ˆ์‹œ ์ฝ”๋“œ

QMember member = QMember.member;

// SELECT * FROM member WHERE username = 'ํ™๊ธธ๋™'
queryFactory.selectFrom(member)
            .where(member.username.eq("ํ™๊ธธ๋™"))
            .fetch();

// WHERE age > 20 AND age < 30
queryFactory.selectFrom(member)
            .where(member.age.gt(20).and(member.age.lt(30)))
            .fetch();

// WHERE username IN ('a', 'b', 'c')
queryFactory.selectFrom(member)
            .where(member.username.in("a", "b", "c"))
            .fetch();

// WHERE age IS NOT NULL
queryFactory.selectFrom(member)
            .where(member.age.isNotNull())
            .fetch();
// UPDATE member SET username = '๋ณ€๊ฒฝ๋จ' WHERE age < 20
queryFactory.update(member)
            .set(member.username, "๋ณ€๊ฒฝ๋จ")
            .where(member.age.lt(20))
            .execute();

// DELETE FROM member WHERE age > 60
queryFactory.delete(member)
            .where(member.age.gt(60))
            .execute();
728x90
320x100