TIL - 20250923

juni·2025년 9월 23일

TIL

목록 보기
134/315

0923 Spring Data JPA & QueryDSL 복습: 효율적인 데이터 접근


✅ 1. Spring Data JPA: JPA 추상화와 생산성 향상

  • Spring Data JPA는 JPA(Java Persistence API)를 더 쉽고 효율적으로 사용할 수 있도록 도와주는 Spring 프레임워크의 모듈입니다. 복잡한 데이터 접근 계층(DAO) 구현을 자동화하여 개발 생산성을 획기적으로 높여줍니다.

➕ 주요 개념 및 특징

  1. Repository 인터페이스:

    • JpaRepository<Entity, ID> 인터페이스를 상속받는 것만으로 기본적인 CRUD(생성, 조회, 수정, 삭제) 메서드(e.g., save(), findById(), findAll(), delete())를 자동으로 제공받습니다.
    • 개발자는 직접 DAO 구현체를 작성할 필요 없이 인터페이스만 정의하면 됩니다.
  2. 쿼리 메서드 (Derived Query Methods):

    • 메서드 이름을 특정 규칙에 따라 작성하면, Spring Data JPA가 해당 이름에 맞는 JPQL(Java Persistence Query Language) 쿼리를 자동으로 생성하여 실행합니다.
    • 예시: findByUsernameAndEmail(String username, String email)
    • 장점: 간단한 쿼리는 SQL 없이 메서드 이름만으로 처리 가능하여 개발 속도가 빠릅니다.
  3. @Query 어노테이션:

    • 쿼리 메서드만으로는 표현하기 어려운 복잡한 JPQL 쿼리나 네이티브 SQL 쿼리를 직접 작성할 수 있도록 지원합니다.
    • value 속성에 JPQL을, nativeQuery = true 설정 시 SQL을 작성합니다.
  4. 페이징 및 정렬:

    • PagingAndSortingRepository를 상속받거나 JpaRepository의 메서드에 Pageable 객체를 인자로 전달하여, 손쉽게 페이징(Pagination) 및 정렬(Sorting) 기능을 구현할 수 있습니다.

✅ 2. QueryDSL: 타입-세이프한 동적 쿼리

  • QueryDSL은 JPQL을 Java 코드로 작성할 수 있게 해주는 프레임워크입니다. 문자열 기반의 JPQL/SQL 쿼리가 아닌, 타입-세이프(Type-safe)한 코드를 통해 쿼리를 구성하여 여러 장점을 제공합니다.

➕ 주요 개념 및 특징

  1. Q-Type (Query Type):

    • QueryDSL은 엔티티 클래스를 기반으로 Q 접두사가 붙은 정적 클래스(Q-Type)를 자동으로 생성합니다 (e.g., User 엔티티 → QUser).
    • 이 Q-Type을 통해 엔티티의 필드에 직접 접근하여 쿼리 조건을 작성할 수 있습니다. (e.g., QUser.user.username.eq("test"))
  2. JPAQueryFactory:

    • QueryDSL 쿼리를 생성하고 실행하는 진입점(Entry Point) 객체입니다. Spring 환경에서는 JPAQueryFactory를 Spring Bean으로 등록하여 주입받아 사용합니다.
  3. 동적 쿼리 (BooleanBuilder):

    • 검색 조건이 동적으로 변하는 경우(e.g., 사용자가 입력한 값에 따라 WHERE 절이 달라지는 경우)에 매우 유용합니다.
    • BooleanBuilder 객체에 if 문 등을 사용하여 조건이 만족할 때만 and(), or() 메서드로 쿼리 조건을 추가합니다.
    BooleanBuilder builder = new BooleanBuilder();
    if (username != null) builder.and(qUser.username.eq(username));
    if (email != null) builder.and(qUser.email.eq(email));
    // factory.selectFrom(qUser).where(builder).fetch();
  4. 서브쿼리 (JPAExpressions):

    • JPAExpressions 유틸리티 클래스를 사용하여 SELECT, WHERE, HAVING 절 등에서 서브쿼리를 작성할 수 있습니다.
    // 특정 그룹의 평균 나이보다 많은 사용자 조회
    // JPAExpressions.select(qUser.age.avg()).from(qUser).where(qUser.group.name.eq("A"))
  5. 동적 정렬 (OrderSpecifier):

    • 사용자의 요청에 따라 정렬 기준(컬럼)과 방향(오름차순/내림차순)이 달라지는 경우에 OrderSpecifier를 사용하여 동적으로 정렬 조건을 구성할 수 있습니다.

✅ 3. Spring Data JPA와 QueryDSL의 통합 (Custom Repository)

  • Spring Data JPA는 간단한 쿼리에 강점을 보이고, QueryDSL은 복잡하고 동적인 쿼리에 강점을 보입니다. 이 둘을 함께 사용하여 효율적인 데이터 접근 계층을 구축하는 것이 일반적입니다.

➕ 통합 패턴: Custom Repository

  1. Custom Repository 인터페이스 정의: QueryDSL로 구현할 메서드를 선언하는 인터페이스를 만듭니다 (e.g., UserRepositoryCustom).
  2. Custom Repository 구현체 작성: 위 인터페이스를 구현하는 클래스를 만들고, JPAQueryFactory를 주입받아 QueryDSL 쿼리 로직을 작성합니다 (e.g., UserRepositoryImpl).
    • 규칙: 구현체 클래스 이름은 [Repository 인터페이스 이름] + Impl 형태로 지어야 Spring Data JPA가 자동으로 연결합니다.
  3. 기존 Repository 인터페이스 확장: JpaRepository를 상속받는 기존 Repository 인터페이스가 Custom Repository 인터페이스를 함께 상속받도록 합니다 (e.g., interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {}).
  • 이러한 구조를 통해, UserRepository는 Spring Data JPA의 기본 CRUD와 쿼리 메서드를 제공하면서, 동시에 QueryDSL로 구현된 복잡한 동적 쿼리 메서드까지 사용할 수 있게 됩니다.

📌 요약

  • Spring Data JPAJpaRepository와 쿼리 메서드를 통해 보일러플레이트 코드를 줄여 개발 생산성을 높입니다.
  • QueryDSLQ-TypeJPAQueryFactory를 사용하여 타입-세이프한 Java 코드로 동적 쿼리를 작성할 수 있게 하여, 컴파일 시점 오류 감지와 높은 가독성을 제공합니다.
  • 이 둘은 Custom Repository 패턴을 통해 효과적으로 통합되어, 간단한 쿼리는 Spring Data JPA로, 복잡하고 동적인 쿼리는 QueryDSL로 처리하는 유연하고 강력한 데이터 접근 계층을 구축할 수 있습니다.

0개의 댓글