💡 개요
오늘은 Spring Framework에서 사용되는 기술인 JPQL과 QueryDsl에 대해 정리해 보자.
📕 JPA
Spring JPA는 Spring에서 Java Persistence API(JPA)를 더욱 편리하게 사용할 수 있도록 지원하는 모듈이다.
JPA를 사용하면 개발자가 직접 쿼리를 작성하지 않아도 되고, 데이터베이스 테이블과 매핑된 엔티티를 통해 데이터를 다룰 수 있다.
또한, JpaRepository를 활용하면 메서드 호출만으로도 필요한 쿼리를 자동으로 생성하고 실행할 수 있어, 데이터베이스 연동을 더욱 간결하고 효율적으로 처리할 수 있다.
public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findMemberByName(String name);
Optional<Member> findMemberByEmail(String email);
...
}
하지만 복잡한 쿼리문을 위의 메서드를 사용하려면 한계가 분명하다.
그렇기 때문에 복잡한 쿼리문에는 JPQL이나 QueryDsl을 주로 사용한다.
🛠️ JPQL (Java Persistence Query Language)
JPQL이란 SQL과 유사하지만 테이블이 아닌 엔티티를 대상으로 쿼리를 작성하는 언어이다.
그렇기 때문에 쿼리문에 작성될 모든 문자열을 개발자가 직접 작성해야 한다.
다음은 JPQL을 사용해 입력된 이메일과 일치하는 Member 정보를 조회하는 코드이다.
String jpql = "SELECT m FROM Member m WHERE m.email = :email";
TypedQuery<Member> query = em.createQuery(jpql, Member.class);
query.setParameter("email", "test@naver.com");
List<Member> result = query.getResultList();
JPQL의 장점은 오직 복잡한 쿼리문을 사용하는 데 있어서 JPA의 메서드 방식보다 적합하다는 것이다.
JPQL의 단점은 위에서 보다시피 쿼리문을 개발자가 직접 작성했다.
String jpql = "SELECT m FROM Member m WHERE m.email = :email";
그렇기 때문에 SQL 문법 오류를 컴파일러가 잡아주지 않는다.
만약 쿼리문이 잘못되었다면 컴파일 시점이 아닌 런타임 시점에 알아차릴 가능성이 커진다.
또한 데이터베이스에 전송하는 쿼리문이 정적이다.
만약 개발자가 저 JPQL 쿼리문을 작성했다면 저 쿼리문만 전송되는 것이다.
🛠️ QueryDSL
QueryDSL은 위에서 언급한 JPQL을 보완한 기술이다.
주요 특징으론 JPQL과 달리 문자열이 아닌 Java 코드 기반으로 쿼리를 작성한다.
그렇기 때문에 쿼리에 문제가 있는 경우 컴파일 시점에 예외가 발생하기 때문에 JPQL보다 더 안전하게 사용할 수 있다.
뿐만 아니라 정적 쿼리와 BooleanBuilder을 사용해 동적 쿼리 둘 다 사용 가능하다.
QMember m = QMember.member;
List<Member> result = queryFactory
.selectFrom(m)
.where(m.email.eq("test@naver.com"))
.fetch();
위의 코드를 보면 JPQL과 달리 메서드 체이닝을 사용하기 때문에 가독성도 좋다.
다음은 동적 쿼리를 사용한 코드이다.
@Repository
@RequiredArgsConstructor
public class MemberQueryRepository {
private final JPAQueryFactory queryFactory;
...
public List<Member> searchMembers(String email) {
QMember m = QMember.member;
BooleanBuilder builder = new BooleanBuilder();
if (email != null && !email.isEmpty()) {
builder.and(m.email.eq(email));
}
return queryFactory
.selectFrom(m)
.where(builder)
.fetch();
}
}
🤔 결론
단순한 정적 쿼리만을 사용해도 된다면 웬만하면 JPA의 메서드를 사용하는 게 편하고 안전하다.
하지만 동적 쿼리가 많아질 가능성이 있거나, 가독성, 유지보수를 고려해야 한다면 QueryDsl을 고려해 보자.
'개발 일기' 카테고리의 다른 글
[개발 일기] 2025.03.08 - MySQL과 웹 애플리케이션 (1) | 2025.03.08 |
---|---|
[개발 일기] 2025.03.07 - Docker 볼륨 설정 (0) | 2025.03.07 |
[개발 일기] 2025.03.05 - 디스크, 파티션, 볼륨 (Docker) (0) | 2025.03.05 |
[개발 일기] 2025.03.04 - RequestDto에 Getter가 없으면 예외? (0) | 2025.03.04 |
[개발 일기] 2025.03.03 - Thread 조정 (동기화) (1) | 2025.03.03 |