Java Persistence API (JPA)는 Java 애플리케이션에서 데이터베이스와 상호작용하기 위한 표준 인터페이스입니다.
Hibernate, EclipseLink와 같은 구현체를 통해 동작.
JPQL (Java Persistence Query Language)로 데이터 조회 및 조작을 수행.
주요 특징
객체지향 프로그래밍 방식.
JPQL을 활용하여 SQL과 유사하지만 엔티티 객체를 다루는 쿼리를 작성.
Spring Data JPA와 같은 라이브러리가 추가 제공하는 메서드 이름 기반 쿼리 생성(예: findByNameAndAge
).
표준화
여러 구현체(Hibernate, EclipseLink 등)에서 동일하게 동작.
Spring Data JPA와 결합하면 사용하기 간단.
생산성 증가
메서드 이름 기반 쿼리 자동 생성 기능.
간단한 쿼리의 경우 Custom Query 없이 처리 가능.
SQL 추상화
JPQL은 SQL을 엔티티 단위로 추상화하여 작성.
객체지향 방식으로 데이터베이스를 다룸.
캐싱 기능
복잡한 쿼리의 가독성 저하
동적 쿼리 제한
동적 쿼리 생성이 어렵고 Criteria API
같은 도구를 사용해야 함.
Criteria API
는 가독성이 낮고 코드가 장황함.
SQL 의존적 기능 부족
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByAgeGreaterThanAndNameContains(int age, String name); // 간단한 메서드 쿼리
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.name LIKE CONCAT('%', :name, '%') AND u.age > :age")
List<User> findUsersByNameAndAge(@Param("name") String name, @Param("age") int age);
}
QueryDSL은 Java와 Kotlin에서 사용하는 타입 안전한 쿼리 언어 구축 라이브러리.
JPA, Hibernate와 통합되어 동적 SQL을 타입 세이프하게 작성 가능.
주요 특징
JPQL 대신 QueryDSL DSL(도메인 특정 언어)로 쿼리를 작성.
컴파일 타임에 쿼리 관련 에러를 줄이고 타입 안전성을 보장.
SQL과 유사한 메서드 체이닝 방식으로 쿼리 작성.
동적 쿼리 작성이 매우 간단
WHERE 조건을 메서드 체이닝으로 추가 가능.
런타임 동적으로 조건을 조절 가능.
타입 안전성
잘못된 필드를 사용하면 컴파일 타임에 오류를 감지.
IDE의 코드 자동 완성 지원.
가독성
메서드 체이닝 방식으로 코드 가독성 및 유지보수가 용이.
복잡한 쿼리도 구조적이고 간결하게 작성 가능.
리팩토링 편의성
Native SQL 수준의 유연성
설정 번거로움
초기 설정에 빌드 플러그인 추가 등 작업 필요.
코드 생성기를 통해 Q클래스 생성이 필요.
학습 곡선
종속성
// 동적 조건을 추가하여 쿼리를 작성
public List<User> searchUsers(String name, Integer age) {
BooleanBuilder builder = new BooleanBuilder();
if (name != null) {
builder.and(QUser.user.name.contains(name));
}
if (age != null) {
builder.and(QUser.user.age.gt(age));
}
return queryFactory.selectFrom(QUser.user)
.where(builder)
.fetch();
}
// 복잡한 JOIN과 프로젝션 사용
public List<UserOrderDto> getUserOrders() {
return queryFactory.select(Projections.constructor(UserOrderDto.class,
user.name, order.productName, order.orderDate))
.from(user)
.join(order).on(user.id.eq(order.userId))
.where(user.age.gt(18))
.fetch();
}
항목 | JPA | QueryDSL |
---|---|---|
동적 쿼리 처리 | 제한적, Criteria API 필요 (코드 장황) | 간편한 메서드 체이닝 및 BooleanBuilder 지원 |
쿼리 검증 | 런타임에 검증 (JPQL 구문 오류는 실행 시 알림) | 컴파일 타임 검증으로 안전성 보장 |
가독성 | JPQL은 복잡한 쿼리에서 가독성 저하 | 간결하고 구조화된 쿼리 문법 |
설정 난이도 | Spring Data JPA 사용 시 쉬움 | 초기 설정(빌드 플러그인, Q클래스 생성 등) 필요 |
작성 자유도 | 객체 중심으로 추상화, SQL 의존적인 기능은 어렵다 | SQL 수준의 복잡한 필터, JOIN 등 유연성 제공 |
러닝 커브 | 쉬움 (Spring Data JPA를 사용하면 더욱 쉬움) | 상대적으로 학습해야 할 것이 많음 |
의존성 | 여러 JPA 구현체 사용 가능 (Hibernate, EclipseLink 등) | QueryDSL 라이브러리에 종속 |
성능 | JPA와 동일, SQL 변환 및 실행 | 동일 (JPA와 Hibernate를 기반으로 동작) |
JPA 사용 추천
간단한 CRUD 및 조건 기반 쿼리.
Spring Data JPA의 메서드 이름 쿼리로 충분할 경우.
복잡한 동적 조건이나 고급 쿼리를 많이 사용하지 않을 경우.
QueryDSL 사용 추천
복잡한 조건 처리와 동적 쿼리가 주요 요구사항일 경우.
SQL 수준의 유연성이 필요하거나 복잡한 JOIN 및 GROUP BY 작업이 많을 경우.
대규모 프로젝트로 체계적이고 안전한 코딩이 필요한 경우.