동적 쿼리

haruceki·2024년 9월 15일
0

동적 쿼리란 쿼리의 조건이나 구조를 실행 시점에 동적으로 변경할 수 있는 SQL 쿼리를 말한다.

즉, 조건에 따라 쿼리를 다르게 구성하거나 필터링, 정렬, 페이징 등을 유연하게 적용할 수 있다. 동적 쿼리를 사용하면 고정된 쿼리 대신 상황에 맟춰 다양한 쿼리를 생성할 수 있기 때문에 복잡한 검색 기능을 구현할 때 주로 사용된다.

동적 쿼리 특징

  1. 조건에 따른 쿼리 생성 : 사용자가 제공한 값에 따라 쿼리의 where 조건을 다르게 설정할 수 있다.
  2. 선택적 필터링 : 여러 조건 중 필요한 조건만 적용하거나 특정 필드를 동적으로 추가/제외할 수 있다.
  3. 다양한 결과 처리 : 필터링, 정렬, 페이징 등의 기능을 상황에 따라 자유롭게 추가할 수 있다.

동적 쿼리의 필요성

정적 쿼리는 고정된 조건으로만 동작하지만, 애플리케이션의 요구사항에 따라 검색 조건이나 필터가 유동적으로 변하는 경우가 많다. 예를 들어, 검색 조건으로 이름, 나이, 지역 등을 사용자가 선택할 수 있다고 가정하면, 각각의 조합에 맞는 수많은 쿼리를 작성하는 대신 동적 쿼리를 통해 하나의 쿼리로 여러 조건을 처리할 수 있다.

동적 쿼리 장점

  1. 재사용성 : 조건이 다르더라도 하나의 메서드로 여러 쿼리를 처리 가능
  2. 유연성 : 사용자 요구 사항에 맞춰 필터 조건, 정렬, 페이징 등을 유연하게 처리 가능
  3. 성능 최적화 : 필요한 조건만 추가하므로 불필요한 조건을 포함하지 않아 성능 향상 가능

동적 쿼리 작성 방법

  • JPQL(Java Persistence Query Language) : 문자열을 기반으로 조건에 따라 SQL 쿼리를 동적으로 생성 가능
  • Criteria API : JPA에서 제공하는 API. 코드가 복잡해질 수 있어 복잡한 동적 쿼리에는 선호되지 않는 편이다.
  • QueryDSL : 타입 세이프한 방식으로 안전하게 동적 쿼리를 작성 가능한 라이브러리. 메서드 체이닝으로 조건을 추가할 수 있어 가독성이 좋고 유지보수가 용이하다.
  • Specification(Spring Datat JPA): 동적 쿼리를 작성시 Predicate로 조건을 추가할 수 있는 방식으로, 객체지향적 접근을 제공해 유지보수에 유리하다.

메서드 체이닝

객체 지향 프로그래밍에서 여러 메서드를 연속적으로 호출할 수 있게 하는 설계 패턴이다. 각 메서드가 호출될 때 자기 자신(객체)을 반환함으로써, 그 객체의 다른 메서드를 이어서 호출할 수 있게 하는 방식이다.
가독성이 좋고, 연속적인 작업 처리에 유용하다.

  • 예시

    //일반적인 코드
    StringBuilder sb = new StringBuilder();
    sb.append("Hello");
    sb.append(" ");
    sb.append("World");
    String result = sb.toString();
    
    //메서드 체이닝을 사용한 코드
    String result = new StringBuilder()
        .append("Hello")
        .append(" ")
        .append("World")
        .toString();
  • querydsl에서 메서드 체이닝

    JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
    QUser user = QUser.user;
    
    List<User> users = queryFactory
        .selectFrom(user)
        .where(user.age.gt(18)
            .and(user.status.eq(Status.ACTIVE)))
        .orderBy(user.name.asc())
        .fetch();

동적 쿼리 예시

  • JPQL로 작성한 예시
public List<User> findUsers(String name, Integer age, String location) {
    String jpql = "SELECT u FROM User u WHERE 1=1";
    
    if (name != null) {
        jpql += " AND u.name = :name";
    }
    if (age != null) {
        jpql += " AND u.age = :age";
    }
    if (location != null) {
        jpql += " AND u.location = :location";
    }
    
    TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
    
    if (name != null) {
        query.setParameter("name", name);
    }
    if (age != null) {
        query.setParameter("age", age);
    }
    if (location != null) {
        query.setParameter("location", location);
    }
    
    return query.getResultList();
}
  • QueryDSL을 사용한 동적 쿼리 예시
public List<User> findUsers(String name, Integer age, String location) {
    QUser user = QUser.user;
    BooleanBuilder builder = new BooleanBuilder();
    
    if (name != null) {
        builder.and(user.name.eq(name));
    }
    if (age != null) {
        builder.and(user.age.eq(age));
    }
    if (location != null) {
        builder.and(user.location.eq(location));
    }
    
    return queryFactory.selectFrom(user)
                       .where(builder)
                       .fetch();
}
profile
희망도 절망도 없이 매일 코딩을 한다.

0개의 댓글