[Spring Boot] NumberExpression 괄호 처리 문제

왔다 정보리·2026년 2월 9일

QueryDSL의 NumberExpression을 사용하면서 계산 결과가 예상과 달라 문제를 겪은 경험이 있다. 해결 방법은 간단했지만 같은 문제를 여러 번 겪었고, 방심해서 놓치기 쉬운 부분이라 생각이 되어 블로그로 과정을 남겨두려 한다!


문제 상황

⭐️ QueryDSL에서 NumberExpression의 메서드 체이닝으로 수식을 작성하면, 코드상으로는 연산 순서가 명확해 보이지만 체이닝을 SQL로 변환할 때 괄호가 자동으로 생성되지 않는다. ⭐️

자바 코드에서 a.add(b).divide(c)라고 작성하면, (a + b) / c를 의도하고 작성했을 확률이 높다. 체이닝 순서대로 먼저 a + b를 계산한 뒤 c로 나누는 것처럼 읽히기 때문이다. 하지만 QueryDSL은 이 체이닝을 SQL로 변환할 때 괄호 없이 연산자를 나열하기 때문에, SQL의 연산자 우선순위 규칙이 그대로 적용되어 의도와 다른 결과가 나올 수 있다.

예시 코드

에러가 발생한 실제 코드는 외부에 공개할 수 없기 때문에 간단한 예시 코드로 대체한다

// 개발자의 의도: (a + b) / c
NumberExpression<Integer> result = a.add(b).divide(c);

의도한 수식

(a + b) / c = (10 + 20) / 5 = 6

실제 생성되는 SQL과 결과

-- 괄호 없이 생성됨
a + b / c
-- SQL 연산자 우선순위에 의해 나눗셈이 먼저 수행됨
10 + 20 / 5 = 14

자바 코드의 메서드 호출 순서는 SQL의 연산 순서를 보장하지 않는다.

해결책

Expressions.numberTemplate()을 사용하여 괄호를 명시적으로 포함할 수 있다.

// ✅ numberTemplate으로 괄호를 직접 명시
NumberExpression<Integer> result = Expressions.numberTemplate(
    Integer.class,
    "({0} + {1}) / {2}",
    a, b, c
);

정리

상황비고
단순 체이닝 (a.multiply(b))우선순위 이슈가 없는 경우 결과에 영향 없음
덧셈/뺄셈 후 곱셈/나눗셈 체이닝SQL 우선순위와 충돌 → numberTemplate 필요
복잡한 수식전체를 numberTemplate으로 작성 권장

메서드 체이닝이 코드의 가독성을 높여주지만, QueryDSL은 체이닝 순서를 SQL 괄호로 변환해주지 않는다. 연산 순서가 중요한 수식에서는 numberTemplate을 통해 괄호를 직접 작성해야 한다!

profile
왔다 정보리

0개의 댓글