[JPA][QueryDSL] QueryDSL이란?

koline·2024년 4월 26일

JPA

목록 보기
8/11

QueryDSL


Spring에서 애플리케이션과 데이터베이스간의 소통을 위해 SQL을 직접적으로 사용하는 MyBatisMyBatis의 단점을 보완해 데이터를 객체로 보는 ORM 방식을 사용하는 인터페이스인 JPA 두가지 방식이 있다.

그 중 JPA의 가장 큰 단점 중 하나는, SQL의 수많은 기능을 Native Query만큼 자유롭게 활용하기는 매우 어렵다는 점이다. 기본적인 CRUD 메서드야 당연히 제공되고 거기에Pageable 객체를 활용한 페이징 등 편리성까지 제공하지만, 조건절만 하나 추가하려고 해도 커스텀 쿼리를 만들어야 한다.

그런데 진짜 문제는 여기서 발생한다. Query 커스텀하기 포스팅을 읽어보면 알 수 있듯이, 이 커스텀 쿼리는 JPQL을 사용하여 생성하는데 String의 형태로 큰따옴표(")에 둘러싸 어노테이션을 사용해 작성한다.

하지만 JPQL의 사용은 JPA의 단점을 보완하지만, 동시에 장점을 퇴색시킨다.

우선 휴먼에러의 가능성이 생긴다. String 형태로 작성되는 만큼 실행되기 전까지는 오탈자 등으로 인한 에러의 확인이 어렵다.

또한 MyBatis와 비교해서 JPA는 데이터를 객체로 보기 때문에 Entity를 수정해주면 관련된 쿼리를 일일히 찾아낼 필요가 없고, 즉 수정이 간편하고 확장이 용이하다는 장점이 있다. 하지만 JPQL을 사용한다면 수정이나 확장시 Entity를 수정하고 해당 Entity를 사용한 쿼리를 모두 수정해야한다.




사용하는 이유


QueryDSLHibernate Query Language(HQL)의 쿼리를 타입에 안전하게(type-safe) 생성 및 관리해주는 Java 프레임워크이다. QueryDSL은 정적 타입을 이용하여 SQL과 같은 쿼리를 생성할 수 있게 해준다.

즉, 위에서 말한 JPQL을 사용할 때 퇴색되는 JPA의 장점을 유지하면서 커스텀 쿼리를 작성할 수 있게 해준다.

QueryDSL 라이브러리를 설치하고 애플리케이션을 빌드하면 지정된 경로에 Q 엔티티가 자동으로 생성된다.

예를 들어 아래와 같은 Member라는 엔티티가 있다고 가정했을때,

// MemberEntity.java
@Getter
@SuperBuilder
@Entity(name = "MemberEntity")
@Table(name = "Member")
public class Member {
	@Id
    @Column(name = "id", unique = true, nullable = false, updatable = false, length = 30)
    private String id;
    
    @Column(name = "email", nullable = false, length = 30)
    private String email;
    
    @Column(name = "name", nullable = false, length = 20)
    private String name;
}

Build하게 되면 지정된 경로에 지정된경로/QMemberEntity.java 파일이 자동생성 될것이다.

이 파일은 MemberEntity의 정보를 그대로 반영하고 있으며 쿼리를 작성하는데 필요한 메소드들도 포함하고 있어 이 객체를 사용해 쿼리를 작성하면 Type-safe한 쿼리를 작성할 수 있는 것이다.

아래는 QueryDSL을 적용한 쿼리 예시이다.

// QueryDSL 적용 예시 코드
@Repository
@RequiredArgsConstructor
public class MemberCustomRepositoryImpl implements MemberCustomRepository {
    private final JPAQueryFactory query;
    @Override
    public boolean existsByMemberEmail(String email) {
        return query.selectOne()
                .from(memberEntity)
                .where(memberEntity.email.eq(email))
                .fetchFirst() != null;
    }
}

여기서 보이는 memberEntity 변수가 바로 QMemberEntity에서 import된 것으로 emmail과 같은 엔티티의 속성부터 eq와 같은 쿼리에 사용되는 메소드까지 포함하고 있다.

또한 한눈에 알 수 있듯이 실제 SQL과 형태가 매우 유사하여 가독성이 좋다.




참조


[JPA] JPA란? - JPA, Hibernate, Spring Data JPA

[JPA] Query 커스텀하기 - Spring Data JPA, @Query, NativeQuery

profile
개발공부를해보자

0개의 댓글